Search Unity

  1. Welcome to the Unity Forums! Please take the time to read our Code of Conduct to familiarize yourself with the forum rules and how to post constructively.
  2. Dismiss Notice

Question Any way to detect drag-and-drop outside of element?

Discussion in 'UI Toolkit' started by tonycoculuzzi, Dec 17, 2021.

  1. tonycoculuzzi

    tonycoculuzzi

    Joined:
    Jun 2, 2011
    Posts:
    301
    Is there a way to detect if an element being dragged is dropped outside the elements which can handle it?

    For example, I have an element handling drag-and-drop, but if I drop the dragged element outside the intended region (for example: elsewhere in the inspector, on another window, etc) I'd like to be able to cancel the drag-and-drop operation when this happens. I feel like this should be handled automatically using DragExitEvent, but currently it isn't.

    (using Unity 2020.3.24f1)
     
  2. sebastiend-unity

    sebastiend-unity

    Unity Technologies

    Joined:
    Nov 9, 2015
    Posts:
    183
    Just tried on my side, I receive both a DragLeaveEvent and a DragExitEvent...my code was very simple:

    Code (CSharp):
    1. using System;
    2. using System.Collections.Generic;
    3. using UnityEditor;
    4. using UnityEngine;
    5. using UnityEngine.UIElements;
    6.  
    7. public class MyElement : VisualElement
    8. {
    9.     public MyElement()
    10.     {
    11.         this.style.width = 300;
    12.         this.style.height = 200;
    13.         this.style.backgroundColor = new Color(0.5f, 0.5f, 0.5f, 1);
    14.         Add(new Label {text = "Drag and drop here"});
    15.         Add(new DraggableLabel() {text = "Drag Me!"});
    16.         RegisterCallback<DragEnterEvent>(e => Debug.Log("DragEnterEvent"));
    17.         RegisterCallback<DragLeaveEvent>(e => Debug.Log("DragLeaveEvent"));
    18.         RegisterCallback<DragUpdatedEvent>(e =>
    19.         {
    20.             Debug.Log("DragUpdatedEvent");
    21.  
    22.             object draggedLabel = DragAndDrop.GetGenericData(DraggableLabel.s_DragDataType);
    23.             if (draggedLabel != null)
    24.                 DragAndDrop.visualMode = DragAndDropVisualMode.Move;
    25.             else
    26.                 DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
    27.         });
    28.         RegisterCallback<DragPerformEvent>(e =>
    29.         {
    30.             Debug.Log("DragPerformEvent");
    31.            
    32.             DragAndDrop.AcceptDrag();
    33.  
    34.             object draggedObject = DragAndDrop.GetGenericData(DraggableLabel.s_DragDataType);
    35.             if (draggedObject != null && draggedObject is DraggableLabel)
    36.             {
    37.                 var label = (DraggableLabel)draggedObject;
    38.                 label.StopDraggingBox(e.localMousePosition);
    39.             }
    40.         });
    41.         RegisterCallback<DragExitedEvent>(e => Debug.Log("DragExitedEvent"));
    42.     }
    43. }
    44.  
    45. public class DraggableLabel : Label
    46. {
    47.     public static string s_DragDataType = "DraggableLabel";
    48.  
    49.     private bool m_GotMouseDown;
    50.     private Vector2 m_MouseOffset;
    51.  
    52.     public DraggableLabel()
    53.     {
    54.           this.style.backgroundColor = new Color(0.5f, 0, 0, 1);
    55.         this.style.width = 60f;
    56.         RegisterCallback<PointerDownEvent>(OnPointerDownEvent);
    57.         RegisterCallback<PointerMoveEvent>(OnPointerMoveEvent);
    58.         RegisterCallback<PointerUpEvent>(OnPointerUpEvent);
    59.     }
    60.  
    61.     void OnPointerDownEvent(PointerDownEvent e)
    62.     {
    63.         if (e.target == this && e.isPrimary && e.button == 0)
    64.         {
    65.             m_GotMouseDown = true;
    66.             m_MouseOffset = e.localPosition;
    67.         }
    68.     }
    69.  
    70.     void OnPointerMoveEvent(PointerMoveEvent e)
    71.     {
    72.         if (m_GotMouseDown && e.isPrimary && e.pressedButtons == 1)
    73.         {
    74.             StartDraggingBox();
    75.             m_GotMouseDown = false;
    76.         }
    77.     }
    78.  
    79.     void OnPointerUpEvent(PointerUpEvent e)
    80.     {
    81.         if (m_GotMouseDown && e.isPrimary && e.button == 0)
    82.         {
    83.             m_GotMouseDown = false;
    84.         }
    85.     }
    86.  
    87.     public void StartDraggingBox()
    88.     {
    89.         DragAndDrop.PrepareStartDrag();
    90.         DragAndDrop.SetGenericData(s_DragDataType, this);
    91.         DragAndDrop.StartDrag(text);
    92.     }
    93.  
    94.     public void StopDraggingBox(Vector2 mousePosition)
    95.     {
    96.         style.top = -m_MouseOffset.y + mousePosition.y;
    97.         style.left = -m_MouseOffset.x + mousePosition.x;
    98.     }
    99. }
    100.  
     
  3. tonycoculuzzi

    tonycoculuzzi

    Joined:
    Jun 2, 2011
    Posts:
    301
    I wonder if this is a version thing, I forgot to mention that I'm on 2020.3.24f1 and DragExitEvent isn't being called at all when releasing a dragged element outside the ui element handling the drag.

    Edit: Ah nope, looks like it still missing in 2021.2.7f1. I'll compare your implementation and see if I missed something on my end.

    Edit 2: Testing your code now, it actually works the same way I mentioned. When you drag the [Drag me!] element outside of the MyElement box, it successfully calls DragLeaveEvent, but dropping outside the MyElement box it fails to call DragExitEvent, so it's impossible to tell when the user has dropped a draggable element outside of the intended area.
     
    Last edited: Jan 5, 2022
  4. Nixaan

    Nixaan

    Joined:
    May 30, 2013
    Posts:
    116
    On 2022.3.11 it is the same,
    DragLeaveEvent
    works but
    DragExitedEvent
    does not.