private void DoDraggingAndSelection(Rect listRect) { Event evt = Event.current; int oldIndex = m_ActiveElement; bool clicked = false; switch (evt.GetTypeForControl(id)) { case EventType.KeyDown: if (GUIUtility.keyboardControl != id) { return; } // if we have keyboard focus, arrow through the list if (evt.keyCode == KeyCode.DownArrow) { m_ActiveElement += 1; evt.Use(); } if (evt.keyCode == KeyCode.UpArrow) { m_ActiveElement -= 1; evt.Use(); } if (evt.keyCode == KeyCode.Escape && GUIUtility.hotControl == id) { GUIUtility.hotControl = 0; m_Dragging = false; evt.Use(); } // don't allow arrowing through the ends of the list m_ActiveElement = Mathf.Clamp(m_ActiveElement, 0, (m_Elements != null) ? m_Elements.ArraySize - 1 : m_ElementList.Count - 1); break; case EventType.MouseDown: if (!listRect.Contains(Event.current.mousePosition) || Event.current.button != 0) { break; } // clicking on the list should end editing any existing edits EasyGUI.EndEditingActiveTextField(); // pick the active element based on click position m_ActiveElement = GetRowIndex(Event.current.mousePosition.y - listRect.y); if (m_Draggable) { // if we can drag, set the hot control and start dragging (storing the offset) m_DragOffset = (Event.current.mousePosition.y - listRect.y) - GetElementYOffset(m_ActiveElement); UpdateDraggedY(listRect); GUIUtility.hotControl = id; m_SlideGroup.Reset(); m_NonDragTargetIndices = new List <int>(); } GrabKeyboardFocus(); evt.Use(); clicked = true; break; case EventType.MouseDrag: if (!m_Draggable || GUIUtility.hotControl != id) { break; } // Set m_Dragging state on first MouseDrag event after we got hotcontrol (to prevent animating elements when deleting elements by context menu) m_Dragging = true; // if we are dragging, update the position UpdateDraggedY(listRect); evt.Use(); break; case EventType.MouseUp: if (!m_Draggable) { // if mouse up was on the same index as mouse down we fire a mouse up callback (useful if for beginning renaming on mouseup) if (onMouseUpCallback != null && IsMouseInsideActiveElement(listRect)) { // set the keyboard control onMouseUpCallback(this); } break; } // hotcontrol is only set when list is draggable if (GUIUtility.hotControl != id) { break; } evt.Use(); m_Dragging = false; try { // What will be the index of this if we release? int targetIndex = CalculateRowIndex(); if (m_ActiveElement != targetIndex) { // if the target index is different than the current index... if (m_SerializedObject != null && m_Elements != null) { // if we are working with Runtime Serialized Properties, we can handle it for you m_Elements.MoveArrayElement(m_ActiveElement, targetIndex); m_SerializedObject.ApplyModifiedProperties(); m_SerializedObject.Update(); } else if (m_ElementList != null) { // we are working with the IList, which is probably of a fixed length System.Object tempObject = m_ElementList[m_ActiveElement]; for (int i = 0; i < m_ElementList.Count - 1; i++) { if (i >= m_ActiveElement) { m_ElementList[i] = m_ElementList[i + 1]; } } for (int i = m_ElementList.Count - 1; i > 0; i--) { if (i > targetIndex) { m_ElementList[i] = m_ElementList[i - 1]; } } m_ElementList[targetIndex] = tempObject; } var oldActiveElement = m_ActiveElement; var newActiveElement = targetIndex; // update the active element, now that we've moved it m_ActiveElement = targetIndex; // give the user a callback if (onReorderCallbackWithDetails != null) { onReorderCallbackWithDetails(this, oldActiveElement, newActiveElement); } else if (onReorderCallback != null) { onReorderCallback(this); } if (onChangedCallback != null) { onChangedCallback(this); } } else { // if mouse up was on the same index as mouse down we fire a mouse up callback (useful if for beginning renaming on mouseup) if (onMouseUpCallback != null) { onMouseUpCallback(this); } } } finally { // It's quite possible a call to EndGUI was made in one of our callbacks // (and thus an ExitGUIException thrown). We still need to cleanup before // we exitGUI proper. GUIUtility.hotControl = 0; m_NonDragTargetIndices = null; } break; } // if the index has changed and there is a selected callback, call it if ((m_ActiveElement != oldIndex || clicked) && onSelectCallback != null) { onSelectCallback(this); } }