private void DrawListContainerAndItems(Rect position, IReorderableListAdaptor adaptor)
{
int initialDropTargetNestedCounterValue = s_DropTargetNestedCounter;
// Get local copy of event information for efficiency.
EventType eventType = Event.current.GetTypeForControl(_controlID);
Vector2 mousePosition = Event.current.mousePosition;
int newTargetIndex = s_TargetIndex;
// Position of first item in list.
float firstItemY = position.y + ContainerStyle.padding.top;
// Maximum position of dragged item.
float dragItemMaxY = (position.yMax - ContainerStyle.padding.bottom) - s_DragItemPosition.height + 1;
bool isMouseDragEvent = eventType == EventType.MouseDrag;
if (s_SimulateMouseDragControlID == _controlID && eventType == EventType.Repaint) {
s_SimulateMouseDragControlID = 0;
isMouseDragEvent = true;
}
if (isMouseDragEvent && _tracking) {
// Reset target index and adjust when looping through list items.
if (mousePosition.y < firstItemY)
newTargetIndex = 0;
else if (mousePosition.y >= position.yMax)
newTargetIndex = adaptor.Count;
s_DragItemPosition.y = Mathf.Clamp(mousePosition.y + s_AnchorMouseOffset, firstItemY, dragItemMaxY);
}
switch (eventType) {
case EventType.MouseDown:
if (_tracking) {
// Cancel drag when other mouse button is pressed.
s_TrackingCancelBlockContext = true;
Event.current.Use();
}
break;
case EventType.MouseUp:
if (_controlID == GUIUtility.hotControl) {
// Allow user code to change control over reordering during drag.
if (!s_TrackingCancelBlockContext && _allowReordering)
AcceptReorderDrag(adaptor);
else
StopTrackingReorderDrag();
Event.current.Use();
}
break;
case EventType.KeyDown:
if (_tracking && Event.current.keyCode == KeyCode.Escape) {
StopTrackingReorderDrag();
Event.current.Use();
}
break;
case EventType.ExecuteCommand:
if (s_ContextControlID == _controlID) {
int itemIndex = s_ContextItemIndex;
try {
DoCommand(s_ContextCommandName, itemIndex, adaptor);
Event.current.Use();
}
finally {
s_ContextControlID = 0;
s_ContextItemIndex = 0;
}
}
break;
case EventType.Repaint:
// Draw caption area of list.
ContainerStyle.Draw(position, GUIContent.none, false, false, false, false);
break;
}
ReorderableListGUI.IndexOfChangedItem = -1;
// Draw list items!
Rect itemPosition = new Rect(position.x + ContainerStyle.padding.left, firstItemY, position.width - ContainerStyle.padding.horizontal, 0);
float targetSlotPosition = dragItemMaxY;
_insertionIndex = 0;
_insertionPosition = itemPosition.yMax;
float lastMidPoint = 0f;
float lastHeight = 0f;
int count = adaptor.Count;
for (int i = 0; i < count; ++i) {
itemPosition.y = itemPosition.yMax;
itemPosition.height = 0;
lastMidPoint = itemPosition.y - lastHeight / 2f;
if (_tracking) {
// Does this represent the target index?
if (i == s_TargetIndex) {
targetSlotPosition = itemPosition.y;
itemPosition.y += s_DragItemPosition.height;
}
// Do not draw item if it is currently being dragged.
// Draw later so that it is shown in front of other controls.
if (i == s_AnchorIndex)
continue;
// Update position for current item.
itemPosition.height = adaptor.GetItemHeight(i) + 4;
lastHeight = itemPosition.height;
}
else {
// Update position for current item.
itemPosition.height = adaptor.GetItemHeight(i) + 4;
lastHeight = itemPosition.height;
// Does this represent the drop insertion index?
float midpoint = itemPosition.y + itemPosition.height / 2f;
if (mousePosition.y > lastMidPoint && mousePosition.y <= midpoint) {
_insertionIndex = i;
_insertionPosition = itemPosition.y;
}
}
if (_tracking && isMouseDragEvent) {
float midpoint = itemPosition.y + itemPosition.height / 2f;
if (s_TargetIndex < i) {
if (s_DragItemPosition.yMax > lastMidPoint && s_DragItemPosition.yMax < midpoint)
newTargetIndex = i;
}
else if (s_TargetIndex > i) {
if (s_DragItemPosition.y > lastMidPoint && s_DragItemPosition.y < midpoint)
newTargetIndex = i;
}
/*if (s_DragItemPosition.y > itemPosition.y && s_DragItemPosition.y <= midpoint)
newTargetIndex = i;
else if (s_DragItemPosition.yMax > midpoint && s_DragItemPosition.yMax <= itemPosition.yMax)
newTargetIndex = i + 1;*/
}
// Draw list item.
DrawListItem(itemPosition, adaptor, i);
// Did list count change (i.e. item removed)?
if (adaptor.Count < count) {
// We assume that it was this item which was removed, so --i allows us
// to process the next item as usual.
count = adaptor.Count;
--i;
continue;
}
// Event has already been used, skip to next item.
if (Event.current.type != EventType.Used) {
switch (eventType) {
case EventType.MouseDown:
if (GUI.enabled && itemPosition.Contains(mousePosition)) {
// Remove input focus from control before attempting a context click or drag.
GUIUtility.keyboardControl = 0;
if (_allowReordering && adaptor.CanDrag(i) && Event.current.button == 0) {
s_DragItemPosition = itemPosition;
BeginTrackingReorderDrag(_controlID, i);
s_AnchorMouseOffset = itemPosition.y - mousePosition.y;
s_TargetIndex = i;
Event.current.Use();
}
}
break;
/* DEBUG
case EventType.Repaint:
GUI.color = Color.red;
GUI.DrawTexture(new Rect(0, lastMidPoint, 10, 1), EditorGUIUtility.whiteTexture);
GUI.color = Color.yellow;
GUI.DrawTexture(new Rect(5, itemPosition.y + itemPosition.height / 2f, 10, 1), EditorGUIUtility.whiteTexture);
GUI.color = Color.white;
break;
//*/
}
}
}
if (HorizontalLineAtEnd) {
var horizontalLinePosition = new Rect(itemPosition.x, position.yMax - ContainerStyle.padding.vertical, itemPosition.width, 1);
GUIHelper.Separator(horizontalLinePosition, HorizontalLineColor);
}
lastMidPoint = position.yMax - lastHeight / 2f;
// Assume that drop insertion is not allowed at this time; we can change our
// mind a little further down ;)
_allowDropInsertion = false;
// Item which is being dragged should be shown on top of other controls!
if (IsTrackingControl(_controlID)) {
if (isMouseDragEvent) {
if (s_DragItemPosition.yMax >= lastMidPoint)
newTargetIndex = count;
s_TargetIndex = newTargetIndex;
// Force repaint to occur so that dragging rectangle is visible.
// But only if this is a real MouseDrag event!!
if (eventType == EventType.MouseDrag)
Event.current.Use();
}
DrawFloatingListItem(adaptor, targetSlotPosition);
/* DEBUG
if (eventType == EventType.Repaint) {
GUI.color = Color.blue;
GUI.DrawTexture(new Rect(100, lastMidPoint, 20, 1), EditorGUIUtility.whiteTexture);
GUI.color = Color.white;
}
//*/
}
else {
// Cannot react to drop insertion if a nested drop target has already reacted!
if (s_DropTargetNestedCounter == initialDropTargetNestedCounterValue) {
if (Event.current.mousePosition.y >= lastMidPoint) {
_insertionIndex = adaptor.Count;
_insertionPosition = itemPosition.yMax;
}
_allowDropInsertion = true;
}
}
// Fake control to catch input focus if auto focus was not possible.
GUIUtility.GetControlID(FocusType.Keyboard);
if (isMouseDragEvent && (Flags & ReorderableListFlags.DisableAutoScroll) == 0 && IsTrackingControl(_controlID))
AutoScrollTowardsMouse();
}