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);
            }
        }