Problem with Selection.objects and DragAndDrop.StartDrag

Hey guys

I am having some difficulty with a custom list which has selection and drag and drop support.

The problem:

  • Select object “D” using the Hierarchy window.
  • Position mouse pointer over object “A” within Test Window.
  • Press and hold left mouse button.
  • Notice that object “A” appears selected in both windows.
  • Drag mouse downward to initiate drag and drop mode.
  • Notice that selection immediately reverts to the pre-mouse-down state.

The video:

The code:

using UnityEngine;
using UnityEditor;

using System.Collections;
using System.Collections.Generic;
using System.Linq;

public class TestWindow : EditorWindow {

	[MenuItem("Window/Test Window")]
	private static void ShowWindow() {
		GetWindow<TestWindow>("Test Window");
	}

	private static IEnumerable<TestBehaviour> GetObjectsInScene() {
		return Resources.FindObjectsOfTypeAll(typeof(TestBehaviour))
			.Where(r => r.hideFlags != HideFlags.NotEditable  r.hideFlags != HideFlags.HideAndDontSave  string.IsNullOrEmpty(AssetDatabase.GetAssetPath(r)  ))
			.Cast<TestBehaviour>()
			.OrderBy(r => r.name);
	}

	private static Vector2 s_MouseAnchorPosition;

	private static GUIStyle s_ListItemStyle;

	private void OnGUI() {
		if (s_ListItemStyle == null)
			s_ListItemStyle = "PR Label";

		GUILayout.Space(-10);

		foreach (var obj in GetObjectsInScene()) {
			int controlID = GUIUtility.GetControlID(FocusType.Passive);

			var content = new GUIContent(obj.name);
			Rect position = GUILayoutUtility.GetRect(content, s_ListItemStyle);
			position.width = Screen.width;

			switch (Event.current.GetTypeForControl(controlID)) {
				case EventType.MouseDown:
					if (Event.current.button == 0  position.Contains(Event.current.mousePosition)) {
						GUIUtility.hotControl = controlID;
						s_MouseAnchorPosition = Event.current.mousePosition;

						// 1. Adjust selection on mouse down.
						Selection.objects = new Object[] { obj.gameObject };

						Event.current.Use();
					}
					break;

				case EventType.MouseDrag:
					if (GUIUtility.hotControl == controlID) {
						// Has user initiated drag and drop by breaking the 6px threshold?
						if (Vector2.Distance(s_MouseAnchorPosition, Event.current.mousePosition) > 6) {
							GUIUtility.hotControl = 0;

							// 2. Start drag and drop.
							DragAndDrop.PrepareStartDrag();
							DragAndDrop.objectReferences = new Object[] { obj };
							DragAndDrop.StartDrag(obj.name);
						}
						Event.current.Use();
					}
					break;

				case EventType.MouseUp:
					if (GUIUtility.hotControl == controlID) {
						GUIUtility.hotControl = 0;
						Event.current.Use();
					}
					break;

				case EventType.Repaint:
					s_ListItemStyle.Draw(position, content, focusedWindow == this, false, Selection.activeObject == obj.gameObject, false);
					break;
			}
		}
	}

	private void OnSelectionChange() {
		Repaint();
	}

	private void OnHierarchyChange() {
		Repaint();
	}
	
}

Notes:

  • The problem occurs as soon as DragAndDrop.StartDrag is invoked.
  • Attempting to immediately restore the selection after starting drag fails.

Any help at fixing this problem would be super useful!

Okay, with thanks to weaksauce in IRC it seems that this problem is limited to Windows… it doesn’t occur on OS X.

So I am assuming that this is a bug with Unity (which I have just reported).

Case 601297