Search Unity

How to use DragAndDrop with VisualElements and Manipulators

Discussion in 'UI Toolkit' started by arielsan, May 25, 2019.

  1. arielsan

    arielsan

    Joined:
    Dec 3, 2013
    Posts:
    47
    Hi, I am trying to use DragAndDrop in a MouseManipulator when dragging the mouse but it is not working, it throws this error:

    Code (CSharp):
    1. Drags can only be started from MouseDown or MouseDrag events
    2. UnityEditor.DragAndDrop:StartDrag(String)
    3. HistoryItemDragManipulator:OnMouseMove(MouseMoveEvent) (at Assets/Gemserk.SelectionHistory/Editor/NewWindow/SelectionHistoryNewWindow.cs:212)
    4. UnityEngine.GUIUtility:ProcessEvent(Int32, IntPtr)
    5.  
    I am using it inside the MouseDown/MouseMove event of the Manipulator but I understand it is processing a queued event from the event dispatcher, so my code is not being performed when an Event of MouseDown or MouseDrag is performed but when the dispatcher sent an EventBase of type MouseMoveEvent or MouseDownEvent.

    Here is my code (based on another example of how to implement drag detection with visual elements):

    Code (CSharp):
    1.     public class HistoryItemDragManipulator : MouseManipulator
    2.     {
    3.         #region Init
    4.         protected bool m_Active;
    5.  
    6.         private Object _historyItem;
    7.        
    8.         public HistoryItemDragManipulator(Object objectAdded)
    9.         {
    10.             _historyItem = objectAdded;
    11.             activators.Add(new ManipulatorActivationFilter { button = MouseButton.LeftMouse });
    12.             m_Active = false;
    13.         }
    14.         #endregion
    15.  
    16.         #region Registrations
    17.         protected override void RegisterCallbacksOnTarget()
    18.         {
    19.             target.RegisterCallback<MouseDownEvent>(OnMouseDown);
    20.             target.RegisterCallback<MouseMoveEvent>(OnMouseMove);
    21.             target.RegisterCallback<MouseUpEvent>(OnMouseUp);
    22.         }
    23.  
    24.         protected override void UnregisterCallbacksFromTarget()
    25.         {
    26.             target.UnregisterCallback<MouseDownEvent>(OnMouseDown);
    27.             target.UnregisterCallback<MouseMoveEvent>(OnMouseMove);
    28.             target.UnregisterCallback<MouseUpEvent>(OnMouseUp);
    29.         }
    30.         #endregion
    31.  
    32.         #region OnMouseDown
    33.         protected void OnMouseDown(MouseDownEvent e)
    34.         {
    35.             Debug.Log("on mouse down");
    36.            
    37.             if (m_Active)
    38.             {
    39.                 Debug.Log("on mouse down and active");
    40.                 e.StopImmediatePropagation();
    41.                 return;
    42.             }
    43.            
    44.             if (CanStartManipulation(e))
    45.             {
    46.                 Debug.Log("on mouse down and can start manipulation");
    47.                 m_Active = true;
    48.                 target.CaptureMouse();
    49.                 e.StopPropagation();
    50.             }
    51.         }
    52.         #endregion
    53.  
    54.         #region OnMouseMove
    55.         protected void OnMouseMove(MouseMoveEvent e)
    56.         {
    57.             if (!m_Active || !target.HasMouseCapture())
    58.                 return;
    59.  
    60.             Debug.Log("on mouse drag");
    61.            
    62.             var historyItem = _historyItem;
    63.            
    64.             DragAndDrop.PrepareStartDrag ();
    65.             DragAndDrop.StartDrag (historyItem.name);
    66.             DragAndDrop.objectReferences = new Object[] { historyItem };
    67.            
    68.             if (EditorUtility.IsPersistent(historyItem)) {
    69.  
    70.                 DragAndDrop.paths = new string[] {
    71.                     AssetDatabase.GetAssetPath(historyItem)
    72.                 };
    73.             }
    74.  
    75.             e.StopPropagation();
    76.         }
    77.         #endregion
    78.  
    79.         #region OnMouseUp
    80.         protected void OnMouseUp(MouseUpEvent e)
    81.         {
    82.             if (!m_Active || !target.HasMouseCapture() || !CanStopManipulation(e))
    83.                 return;
    84.  
    85.             m_Active = false;
    86.             target.ReleaseMouse();
    87.             e.StopPropagation();
    88.         }
    89.         #endregion
    90.     }
    Is it possible to use the DragAndDrop with VisualElements? can you recommend a way? couldn't find any examples of this.

    Thanks
     
  2. patrickf

    patrickf

    Unity Technologies

    Joined:
    Oct 24, 2016
    Posts:
    57
    Hi! Yes, it is possible to use the DragAndDrop with VisualElements. You are getting this error because for some reason you call DragAndDrop.StartDrag() when the mouse button is not down (maybe because target.HasMouseCapture() is false in the OnMouseUp(); mouse capture can be stolen). Here is an example of drag an drop, for both the drop area and the draggable element. It was written for 2019.3 but should work with minor modifications in the currently released version.

    This code should be published soon to https://github.com/Unity-Technologies/UIElementsExamples

    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using UnityEditor;
    4. using UnityEngine;
    5. using UnityEngine.UIElements;
    6.  
    7. namespace UIElementsExamples
    8. {
    9.     public class E18_DragAndDrop : EditorWindow
    10.     {
    11.         [MenuItem("UIElementsExamples/18_DragAndDrop")]
    12.         public static void ShowExample()
    13.         {
    14.             E18_DragAndDrop window = GetWindow<E18_DragAndDrop>();
    15.             window.minSize = new Vector2(450, 514);
    16.             window.titleContent = new GUIContent("Example 18");
    17.         }
    18.  
    19.         private VisualElement m_DropArea;
    20.         private Label m_Ghost;
    21.  
    22.         public void OnEnable()
    23.         {
    24.             var root = rootVisualElement;
    25.             root.styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/Editor/dnd.uss"));
    26.  
    27.             m_DropArea = new VisualElement();
    28.             m_DropArea.AddToClassList("droparea");
    29.             m_DropArea.Add(new Label {text = "Drag and drop anything here"});
    30.             root.Add(m_DropArea);
    31.  
    32.             m_Ghost = new Label();
    33.             m_Ghost.AddToClassList("ghost");
    34.             m_DropArea.Add(m_Ghost);
    35.  
    36.             m_DropArea.RegisterCallback<DragEnterEvent>(OnDragEnterEvent);
    37.             m_DropArea.RegisterCallback<DragLeaveEvent>(OnDragLeaveEvent);
    38.             m_DropArea.RegisterCallback<DragUpdatedEvent>(OnDragUpdatedEvent);
    39.             m_DropArea.RegisterCallback<DragPerformEvent>(OnDragPerformEvent);
    40.             m_DropArea.RegisterCallback<DragExitedEvent>(OnDragExitedEvent);
    41.         }
    42.  
    43.         void OnDragEnterEvent(DragEnterEvent e)
    44.         {
    45.             m_DropArea.AddToClassList("dragover");
    46.             m_Ghost.AddToClassList("visible");
    47.             m_Ghost.style.left = e.localMousePosition.x - m_Ghost.resolvedStyle.width / 2;
    48.             m_Ghost.style.top = e.localMousePosition.y - m_Ghost.resolvedStyle.height / 2;
    49.             m_Ghost.text = "";
    50.  
    51.             object draggedLabel = DragAndDrop.GetGenericData(DraggableLabel.s_DragDataType);
    52.             if (draggedLabel != null)
    53.             {
    54.                 var label = (DraggableLabel)draggedLabel;
    55.                 m_Ghost.text = label.text;
    56.  
    57.                 // if mouse exited then re-entered drop area, we need to call PrepareDraggingBox again.
    58.                 label.PrepareDraggingBox();
    59.  
    60.                 label.StartDraggingBox();
    61.             }
    62.             else
    63.             {
    64.                 List<string> names = new List<string>();
    65.                 foreach (var obj in DragAndDrop.objectReferences)
    66.                 {
    67.                     names.Add(obj.name);
    68.                 }
    69.  
    70.                 m_Ghost.text = String.Join(", ", names);
    71.             }
    72.         }
    73.  
    74.         void OnDragLeaveEvent(DragLeaveEvent e)
    75.         {
    76.             m_DropArea.RemoveFromClassList("dragover");
    77.             m_Ghost.RemoveFromClassList("visible");
    78.  
    79.             object draggedLabel = DragAndDrop.GetGenericData(DraggableLabel.s_DragDataType);
    80.             if (draggedLabel != null)
    81.             {
    82.                 var label = (DraggableLabel)draggedLabel;
    83.                 label.StopDraggingBox();
    84.             }
    85.         }
    86.  
    87.         void OnDragUpdatedEvent(DragUpdatedEvent e)
    88.         {
    89.             m_Ghost.style.left = e.localMousePosition.x - m_Ghost.resolvedStyle.width / 2;
    90.             m_Ghost.style.top = e.localMousePosition.y - m_Ghost.resolvedStyle.height / 2;
    91.  
    92.             object draggedLabel = DragAndDrop.GetGenericData(DraggableLabel.s_DragDataType);
    93.             if (draggedLabel != null)
    94.             {
    95.                 DragAndDrop.visualMode = DragAndDropVisualMode.Move;
    96.             }
    97.             else
    98.             {
    99.                 DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
    100.             }
    101.         }
    102.  
    103.         void OnDragPerformEvent(DragPerformEvent e)
    104.         {
    105.             DragAndDrop.AcceptDrag();
    106.  
    107.             object draggedLabel = DragAndDrop.GetGenericData(DraggableLabel.s_DragDataType);
    108.             if (draggedLabel != null)
    109.             {
    110.                 var label = (DraggableLabel)draggedLabel;
    111.                 label.style.top = m_Ghost.resolvedStyle.top;
    112.                 label.style.left = m_Ghost.resolvedStyle.left;
    113.                 label.StopDraggingBox();
    114.             }
    115.             else
    116.             {
    117.                 var newBox = new DraggableLabel();
    118.                 newBox.AddToClassList("box");
    119.                 newBox.style.top = m_Ghost.resolvedStyle.top;
    120.                 newBox.style.left = m_Ghost.resolvedStyle.left;
    121.                 newBox.text = m_Ghost.text;
    122.                 // Insert before ghost
    123.                 m_DropArea.Insert(m_DropArea.childCount - 1, newBox);
    124.             }
    125.         }
    126.  
    127.         void OnDragExitedEvent(DragExitedEvent e)
    128.         {
    129.             // Never called at the moment due to a bug. Listen to DragLeaveEvent instead.
    130.             Debug.Log("Should not be called unless bug was fixed.");
    131.         }
    132.     }
    133.  
    134.     public class DraggableLabel : Label
    135.     {
    136.         public static string s_DragDataType = "DraggableLabel";
    137.  
    138.         enum DragState
    139.         {
    140.             AtRest,
    141.             Ready,
    142.             Dragging
    143.         }
    144.  
    145.         private DragState m_DragState;
    146.  
    147.         public DraggableLabel()
    148.         {
    149.             m_DragState = DragState.AtRest;
    150.  
    151.             RegisterCallback<MouseDownEvent>(OnMouseDownEvent);
    152.             RegisterCallback<MouseMoveEvent>(OnMouseMoveEvent);
    153.             RegisterCallback<MouseUpEvent>(OnMouseUpEvent);
    154.         }
    155.  
    156.         void OnMouseDownEvent(MouseDownEvent e)
    157.         {
    158.             if (e.target == this && e.button == 0)
    159.             {
    160.                 PrepareDraggingBox();
    161.             }
    162.         }
    163.  
    164.         public void PrepareDraggingBox()
    165.         {
    166.             m_DragState = DragState.Ready;
    167.         }
    168.  
    169.         void OnMouseMoveEvent(MouseMoveEvent e)
    170.         {
    171.             if (m_DragState == DragState.Ready)
    172.             {
    173.                 DragAndDrop.PrepareStartDrag();
    174.                 DragAndDrop.SetGenericData(s_DragDataType, this);
    175.                 DragAndDrop.StartDrag(text);
    176.                 StartDraggingBox();
    177.             }
    178.         }
    179.  
    180.         void OnMouseUpEvent(MouseUpEvent e)
    181.         {
    182.             if (m_DragState == DragState.Ready && e.button == 0)
    183.             {
    184.                 StopDraggingBox();
    185.             }
    186.         }
    187.  
    188.         public void StartDraggingBox()
    189.         {
    190.             AddToClassList("dragged");
    191.             m_DragState = DragState.Dragging;
    192.         }
    193.  
    194.         public void StopDraggingBox()
    195.         {
    196.             RemoveFromClassList("dragged");
    197.             m_DragState = DragState.AtRest;
    198.         }
    199.     }
    200. }
    201.  

    .droparea {
    position: absolute;
    top: 20px;
    left: 20px;
    bottom: 20px;
    right: 20px;
    background-color: azure;
    border-width: 5px;
    border-color: azure;
    }

    Label {
    color: darkslategray;
    -unity-text-align: upper-center;
    }

    .droparea.dragover {
    border-width: 5px;
    border-color: red;
    }

    .ghost {
    -unity-text-align: upper-left;
    display: none;
    position: absolute;
    width: 64px;
    height: 64px;
    background-color: rgba(100, 149, 237, 0.6);
    color: #393636;
    white-space: normal;
    }

    .ghost.visible {
    display: flex;
    }

    .box {
    position: absolute;
    width: 64px;
    height: 64px;
    background-color: darkblue;
    color: antiquewhite;
    white-space: normal;
    border-width: 1px;
    border-color: orange;
    }

    .box.dragged {
    background-color: rgba(0, 0, 139, .6);
    }
     
  3. arielsan

    arielsan

    Joined:
    Dec 3, 2013
    Posts:
    47
    Thanks! will test it right away!
     
  4. arielsan

    arielsan

    Joined:
    Dec 3, 2013
    Posts:
    47
    It worked!!! :)

    I had some issues making the uss working since my current version of UIElements doesn't support some color definitions but I changed them to rgba() and the problem was fixed.

    Also, I added an example of using the dragging objects back when dragging from the container of elements, so you can throw prefabs for example to the drag box and then throw them back to the scene and they are instantiated (that is the use case I wanted). Pasting it here in case you want to add it to the example:

    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using UnityEditor;
    4. using UnityEngine;
    5. using UnityEngine.UIElements;
    6. using Object = UnityEngine.Object;
    7.  
    8. namespace UIElementsExamples
    9. {
    10.     public class E18_DragAndDrop : EditorWindow
    11.     {
    12.         [MenuItem("UIElementsExamples/18_DragAndDrop")]
    13.         public static void ShowExample()
    14.         {
    15.             E18_DragAndDrop window = GetWindow<E18_DragAndDrop>();
    16.             window.minSize = new Vector2(450, 514);
    17.             window.titleContent = new GUIContent("Example 18");
    18.         }
    19.         private VisualElement m_DropArea;
    20.         private Label m_Ghost;
    21.  
    22.         private Object[] m_objectReferences;
    23.         public void OnEnable()
    24.         {
    25.             var root = rootVisualElement;
    26.             root.styleSheets.Add(AssetDatabase.LoadAssetAtPath<StyleSheet>("Assets/Editor/DragAndDrop/E18_DragAndDrop.uss"));
    27.             m_DropArea = new VisualElement();
    28.             m_DropArea.AddToClassList("droparea");
    29.             m_DropArea.Add(new Label {text = "Drag and drop anything here"});
    30.             root.Add(m_DropArea);
    31.             m_Ghost = new Label();
    32.             m_Ghost.AddToClassList("ghost");
    33.             m_DropArea.Add(m_Ghost);
    34.             m_DropArea.RegisterCallback<DragEnterEvent>(OnDragEnterEvent);
    35.             m_DropArea.RegisterCallback<DragLeaveEvent>(OnDragLeaveEvent);
    36.             m_DropArea.RegisterCallback<DragUpdatedEvent>(OnDragUpdatedEvent);
    37.             m_DropArea.RegisterCallback<DragPerformEvent>(OnDragPerformEvent);
    38.             m_DropArea.RegisterCallback<DragExitedEvent>(OnDragExitedEvent);
    39.         }
    40.         void OnDragEnterEvent(DragEnterEvent e)
    41.         {
    42.             m_DropArea.AddToClassList("dragover");
    43.             m_Ghost.AddToClassList("visible");
    44.             m_Ghost.style.left = e.localMousePosition.x - m_Ghost.resolvedStyle.width / 2;
    45.             m_Ghost.style.top = e.localMousePosition.y - m_Ghost.resolvedStyle.height / 2;
    46.             m_Ghost.text = "";
    47.          
    48.             m_objectReferences = null;
    49.  
    50.             object draggedLabel = DragAndDrop.GetGenericData(DraggableLabel.s_DragDataType);
    51.             if (draggedLabel != null)
    52.             {
    53.                 var label = (DraggableLabel)draggedLabel;
    54.                 m_Ghost.text = label.text;
    55.                 // if mouse exited then re-entered drop area, we need to call PrepareDraggingBox again.
    56.                 label.PrepareDraggingBox();
    57.                 label.StartDraggingBox();
    58.             }
    59.             else
    60.             {
    61.                 List<string> names = new List<string>();
    62.                 foreach (var obj in DragAndDrop.objectReferences)
    63.                 {
    64.                     names.Add(obj.name);
    65.                 }
    66.                 m_Ghost.text = String.Join(", ", names);
    67.                 m_objectReferences = DragAndDrop.objectReferences;
    68.             }
    69.         }
    70.         void OnDragLeaveEvent(DragLeaveEvent e)
    71.         {
    72.             m_DropArea.RemoveFromClassList("dragover");
    73.             m_Ghost.RemoveFromClassList("visible");
    74.             object draggedLabel = DragAndDrop.GetGenericData(DraggableLabel.s_DragDataType);
    75.             if (draggedLabel != null)
    76.             {
    77.                 var label = (DraggableLabel)draggedLabel;
    78.                 label.StopDraggingBox();
    79.             }
    80.         }
    81.         void OnDragUpdatedEvent(DragUpdatedEvent e)
    82.         {
    83.             m_Ghost.style.left = e.localMousePosition.x - m_Ghost.resolvedStyle.width / 2;
    84.             m_Ghost.style.top = e.localMousePosition.y - m_Ghost.resolvedStyle.height / 2;
    85.             object draggedLabel = DragAndDrop.GetGenericData(DraggableLabel.s_DragDataType);
    86.             if (draggedLabel != null)
    87.             {
    88.                 DragAndDrop.visualMode = DragAndDropVisualMode.Move;
    89.             }
    90.             else
    91.             {
    92.                 DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
    93.             }
    94.         }
    95.         void OnDragPerformEvent(DragPerformEvent e)
    96.         {
    97.             DragAndDrop.AcceptDrag();
    98.             object draggedLabel = DragAndDrop.GetGenericData(DraggableLabel.s_DragDataType);
    99.             if (draggedLabel != null)
    100.             {
    101.                 var label = (DraggableLabel)draggedLabel;
    102.                 label.style.top = m_Ghost.resolvedStyle.top;
    103.                 label.style.left = m_Ghost.resolvedStyle.left;
    104.                 label.StopDraggingBox();
    105.             }
    106.             else
    107.             {
    108.                 var newBox = new DraggableLabel();
    109.                 newBox.AddToClassList("box");
    110.                 newBox.style.top = m_Ghost.resolvedStyle.top;
    111.                 newBox.style.left = m_Ghost.resolvedStyle.left;
    112.                 newBox.text = m_Ghost.text;
    113.                 newBox.m_objectReferences = m_objectReferences;
    114.                 // Insert before ghost
    115.                 m_DropArea.Insert(m_DropArea.childCount - 1, newBox);
    116.             }
    117.         }
    118.         void OnDragExitedEvent(DragExitedEvent e)
    119.         {
    120.             // Never called at the moment due to a bug. Listen to DragLeaveEvent instead.
    121.             Debug.Log("Should not be called unless bug was fixed.");
    122.         }
    123.     }
    124.     public class DraggableLabel : Label
    125.     {
    126.         public static string s_DragDataType = "DraggableLabel";
    127.         enum DragState
    128.         {
    129.             AtRest,
    130.             Ready,
    131.             Dragging
    132.         }
    133.         private DragState m_DragState;
    134.      
    135.         public Object[] m_objectReferences;
    136.         public DraggableLabel()
    137.         {
    138.             m_DragState = DragState.AtRest;
    139.             RegisterCallback<MouseDownEvent>(OnMouseDownEvent);
    140.             RegisterCallback<MouseMoveEvent>(OnMouseMoveEvent);
    141.             RegisterCallback<MouseUpEvent>(OnMouseUpEvent);
    142.         }
    143.         void OnMouseDownEvent(MouseDownEvent e)
    144.         {
    145.             if (e.target == this && e.button == 0)
    146.             {
    147.                 PrepareDraggingBox();
    148.             }
    149.         }
    150.         public void PrepareDraggingBox()
    151.         {
    152.             m_DragState = DragState.Ready;
    153.         }
    154.         void OnMouseMoveEvent(MouseMoveEvent e)
    155.         {
    156.             if (m_DragState == DragState.Ready)
    157.             {
    158.                 DragAndDrop.PrepareStartDrag();
    159.                 DragAndDrop.SetGenericData(s_DragDataType, this);
    160.                 DragAndDrop.StartDrag(text);
    161.                 DragAndDrop.objectReferences = m_objectReferences;
    162.                 StartDraggingBox();
    163.             }
    164.         }
    165.         void OnMouseUpEvent(MouseUpEvent e)
    166.         {
    167.             if (m_DragState == DragState.Ready && e.button == 0)
    168.             {
    169.                 StopDraggingBox();
    170.             }
    171.         }
    172.         public void StartDraggingBox()
    173.         {
    174.             AddToClassList("dragged");
    175.             m_DragState = DragState.Dragging;
    176.         }
    177.         public void StopDraggingBox()
    178.         {
    179.             RemoveFromClassList("dragged");
    180.             m_DragState = DragState.AtRest;
    181.         }
    182.     }
    183. }
    184.  
     
  5. arielsan

    arielsan

    Joined:
    Dec 3, 2013
    Posts:
    47
    Well DragAndDrop still doesn't work on Mac in Unity 2019 or I don't know how to use it. It works fine on Windows.
     
  6. patrickf

    patrickf

    Unity Technologies

    Joined:
    Oct 24, 2016
    Posts:
    57
    For some reasons, it looks like OnDragEnterEvent is not called on MacOS. To make it work, move the entire OnDragEnterEvent() code in a new StartDragging(IMouseEvent e) function. Call StartDragging() in OnDragEnterEvent() and at the start of OnDragUpdatedEvent(), if you are not already dragging.
     
  7. arielsan

    arielsan

    Joined:
    Dec 3, 2013
    Posts:
    47
    Didn't work but I might be doing something wrong, will try again later.
     
  8. cecarlsen

    cecarlsen

    Joined:
    Jun 30, 2006
    Posts:
    864
    Just a note to others who want to use DragAndDrop together with the DragEvents in UIElements.

    I spend hours getting it working, and when it finally worked, I realized that it (seemingly) is designed for other problems than what I was trying to solve. I wanted to drag nodes and connections between nodes around inside a single window.

    If you want to drag a kind of asset or scene object around between windows, perhaps interacting with build-in editor windows, use it. ELSE if you want to create special in-window drag interaction then don't use it. Just stick to the MouseEvents. Here is why I think so:
    • For DragPerformEvent to be send you must set DragAndDrop.visualMode to something else than None or Rejected. Setting visualMode will change the look of your cursor, and you might not want that.
    • DragAndDrop.objectReferences contain UnityEngine.Objects and therefore cannot contain VisualElements. This is inconvenient if you have VisualElements that are not associated with a specific UnityEngine.Object.
    • Finally, in my solution using DragAndDrop just made my code unnecessarily over-complicated.

    "DragAndDrop" sounds so general, but it is not designed to be used for every drag interaction.
     
  9. andysaia

    andysaia

    Joined:
    Nov 2, 2015
    Posts:
    21
    I also can't get DragAndDrop working correctly on Mac in Unity 2019.3.7f1 and also can't seem to figure out the workaround.

    The following code works fine on windows but fails on mac.
    Code (CSharp):
    1.         button.RegisterCallback<MouseDownEvent>(mouseDownEvent =>
    2.         {
    3.             DragAndDrop.PrepareStartDrag();
    4.             DragAndDrop.StartDrag("Dragging");
    5.             DragAndDrop.objectReferences = new UnityEngine.Object[] { data.prefab };
    6.         });
    7.  
    8.         button.RegisterCallback<DragUpdatedEvent>(dragUpdatedEvent =>
    9.         {
    10.             dragUpdatedEvent.StopPropagation();
    11.             DragAndDrop.visualMode = DragAndDropVisualMode.Move;
    12.         });
     
  10. XynanXDB

    XynanXDB

    Joined:
    Jan 17, 2017
    Posts:
    9
    If anyone come across this, you could try overriding
    ExecuteDefaultAction(EventBase E)
    . My guess is RegisterCallback only handles callbacks which are events called AFTER the actual events are handled. The actual event handler is ExecuteDefaultAction().

    Code (CSharp):
    1.  
    2. protected override void ExecuteDefaultAction(EventBase E)
    3. {
    4.      base.ExecuteDefaultAction(E);
    5.      OnMouseDown(E);
    6. }
    7.  
    8. void OnMouseDown(EventBase E)
    9. {
    10.      if (E.currentTarget == this && E.eventTypeId == MouseDownEvent.TypeId())
    11.      {
    12.            DragAndDrop.PrepareStartDrag();
    13.            DragAndDrop.SetGenericData("DragSelection", this);
    14.            DragAndDrop.StartDrag("DragSelection");
    15.      }
    16. }
    17.  
    I didn't test this on Mac, but it sure it did solve the "Drags can only be started from MouseDown or MouseDrag events" error.
     
    Yecats likes this.
  11. dyburke

    dyburke

    Joined:
    Nov 11, 2012
    Posts:
    16
    AND DragAndDrop.visualMode must be set during the DragUpdatedEvent. Something easy to miss if, like me, you only read the DragPerformEvent section where it just mentions it needs to be set.
     
  12. herra_lehtiniemi

    herra_lehtiniemi

    Joined:
    Feb 12, 2017
    Posts:
    133
    @patrickf I'm trying to follow your example, but when I call StartDrag, I get this error:

    Code (CSharp):
    1. NullReferenceException: Object reference not set to an instance of an object
    2. UnityEditor.DragAndDrop.StartDrag (System.String title) (at /Users/bokken/buildslave/unity/build/Editor/Mono/DragAndDrop.bindings.cs:207)
    3. Fjylling.DraggableVisualElement.OnMouseMoveEvent (UnityEngine.UIElements.MouseMoveEvent e) (at Assets/Fjylling/Scripts/RuntimeScriptEditorController.cs:85)
    This comes when I call DragAndDrop.StartDrag with any parameter. I'm currently trying to call StartDrag with the s_DragDataType-parameter from your example, but I tried other strings as well and I always get this null error on that particular line. What can this be?

    Running Unity 2022.1.0b6 on Silicon editor.
     
    Last edited: Feb 8, 2022
  13. patrickf

    patrickf

    Unity Technologies

    Joined:
    Oct 24, 2016
    Posts:
    57
    It seems that Event.current is null when you call StartDrag(). Are you calling this as part of an event callback?
     
  14. robi_ham

    robi_ham

    Unity Technologies

    Joined:
    Nov 5, 2020
    Posts:
    1
    I also found the problem that drag and drop was working on Windows but not on MacOS.
    What fixed it was to set
    Code (CSharp):
    1.   DragAndDrop.objectReferences = new Object[] {};
    even when not using it.

    So our setup looks like

    Code (CSharp):
    1.   DragAndDrop.PrepareStartDrag();
    2.   DragAndDrop.objectReferences = new Object[] {};
    3.   DragAndDrop.StartDrag("Dragging VisualElement");
    I reported this issue. Maybe it helps in the meantime.
     
  15. Keepabee

    Keepabee

    Joined:
    Jul 12, 2012
    Posts:
    58
    I'm sorry but I can't make heads or tails of these examples - I'm looking for a way to drag assets from Project View into a custom UIToolkit Inspector and in the custom Inspector code react to the assets being dropped on it by reading the list of dropped assets.

    These examples are littered with CSS stylings to display various visual finery, ghosts, draggable labels and whatnots - I can't make sense of the use-case portrayed here or in any way translate what's done here to what I need in simple terms and minimal examples.

    Can anyone help with such a minimal example, not focused on any extra features or visuals/CSS?
     
  16. a436t4ataf

    a436t4ataf

    Joined:
    May 19, 2013
    Posts:
    1,933
    @Keepabee that was almost exactly my use-case too. @patrickf's first code sample worked perfectly for me - just delete the single line that tries to use USS, and ignore the CSS/USS styles you don't need them. You can manage the visuals however you want in code.

    The modification I made was:

    1. replace lines 117-123 with a single call to a new abstract method "ProcessDragDropOfAsset( Object )" and passes it the "reference" variable. Then the entire class can be ignored: just subclass it and override ProcessDragDropOfAsset, making your codebase a lot cleaner than this 200 line distraction.

    Code (CSharp):
    1. /********* process it ******************/
    2.                 {
    3.                     Object reference = DragAndDrop.objectReferences[0];
    4.                     ProcessDragDropOfAsset( reference );
    5.                 }
    2. comment-out (eventually: delete) every line that deals with the 'm_Ghost', because I wanted a "pure" drag/drop with no visual weirdness.