//********************************** Banshee Engine (www.banshee3d.com) **************************************************// //**************** Copyright (c) 2016 Marko Pintera (marko.pintera@gmail.com). All rights reserved. **********************// using System; using bs; namespace bs.Editor { /** @addtogroup Library * @{ */ /// /// Handles various types of drag and drop operations used by the library window. /// public class LibraryDropTarget { private const int DragStartDistancePx = 3; /// /// Triggered when a resource drag and drop operation occured over the drop target. /// public Action OnDropResource; /// /// Triggered when a scene object drag and drop operation occured over the drop target. /// public Action OnDropSceneObject; /// /// Triggered when a local drag and drop operation is starting (pointer has been pressed and is being dragged while /// within the drop target). /// public Action OnStart; /// /// Triggered when a pointer enters the drop target area while a drag operation is in progress. /// public Action OnEnter; /// /// Triggered when a pointer leaves the drop target area while a drag operation is in progress. /// public Action OnLeave; /// /// Triggered when a pointer moves within the drop target area while a drag operation is in progress. /// public Action OnDrag; /// /// Triggered when a locally initiated (started within the drop target) drag and drop operation ends. /// public Action OnEnd; private readonly EditorWindow parentWindow; private OSDropTarget dropTargetOS; private Rect2I bounds; private bool isMouseDown; private bool isLocalDragInProgress; private bool triggerStartLocalDrag; private bool triggerEndLocalDrag; private bool isDragInBounds; private bool isOSDragActive; private Vector2I mouseDownScreenPos; private Vector2I lastDragWindowPos; /// /// Area inside which drag and drop operations are allowed to occurr. Relative to the parent library window. /// public Rect2I Bounds { get { return bounds; } set { bounds = value; dropTargetOS.Bounds = bounds; } } /// /// Creates a new library drop target. /// /// Window the drop target is part of. public LibraryDropTarget(EditorWindow window) { parentWindow = window; dropTargetOS = new OSDropTarget(window); dropTargetOS.OnDrag += DoOnOSDrag; dropTargetOS.OnDrop += DoOnOSDrop; dropTargetOS.OnEnter += DoOnOSDragEnter; dropTargetOS.OnLeave += DoOnOSDragLeave; EditorInput.OnPointerPressed += Input_OnPointerPressed; EditorInput.OnPointerReleased += Input_OnPointerReleased; EditorInput.OnPointerMoved += Input_OnPointerMoved; } /// /// Triggered when the pointer moved. /// /// Data about the pointer move event. void Input_OnPointerMoved(PointerEvent ev) { Vector2I currentWindowPos = parentWindow.ScreenToWindowPos(ev.ScreenPos); if (isMouseDown && !isLocalDragInProgress) { Vector2I startWindowPos = parentWindow.ScreenToWindowPos(mouseDownScreenPos); if (!Bounds.Contains(startWindowPos)) return; int distance = Vector2I.Distance(startWindowPos, currentWindowPos); if (distance >= DragStartDistancePx) triggerStartLocalDrag = true; } } /// /// Triggered when the pointer is released. /// /// Data about the pointer release event. void Input_OnPointerReleased(PointerEvent ev) { if (isLocalDragInProgress) triggerEndLocalDrag = true; isLocalDragInProgress = false; isMouseDown = false; isDragInBounds = false; triggerStartLocalDrag = false; } /// /// Triggered when the pointer is pressed. /// /// Data about the pointer press event. void Input_OnPointerPressed(PointerEvent ev) { Vector2I currentWindowPos = parentWindow.ScreenToWindowPos(ev.ScreenPos); if (Bounds.Contains(currentWindowPos)) { isMouseDown = true; mouseDownScreenPos = ev.ScreenPos; } } /// /// Triggers events and queries for changes in drag and drop operations. Should be called every frame. /// public void Update() { Vector2I currentWindowPos = parentWindow.ScreenToWindowPos(Input.PointerPosition); if (triggerStartLocalDrag) { isLocalDragInProgress = true; triggerStartLocalDrag = false; if (OnStart != null) OnStart(currentWindowPos); } if (triggerEndLocalDrag) { triggerEndLocalDrag = false; if (OnEnd != null) OnEnd(currentWindowPos); } if (isOSDragActive) return; bool externalDragInProgress = DragDrop.DragInProgress && DragDrop.Type == DragDropType.SceneObject; if (isLocalDragInProgress || externalDragInProgress) { if (lastDragWindowPos != currentWindowPos) { if (!isDragInBounds) { if (Bounds.Contains(currentWindowPos)) { isDragInBounds = true; if (OnEnter != null) OnEnter(currentWindowPos); } } if (OnDrag != null) OnDrag(currentWindowPos); if (isDragInBounds) { if (!Bounds.Contains(currentWindowPos)) { isDragInBounds = false; if (OnLeave != null) OnLeave(); } } lastDragWindowPos = currentWindowPos; } } if (DragDrop.DropInProgress && Bounds.Contains(currentWindowPos)) { if (DragDrop.Type == DragDropType.Resource) { if (OnDropResource != null) { ResourceDragDropData resourceDragDrop = (ResourceDragDropData)DragDrop.Data; OnDropResource(currentWindowPos, resourceDragDrop.Paths); } } else if (DragDrop.Type == DragDropType.SceneObject) { if (OnDropSceneObject != null) { SceneObjectDragDropData sceneDragDrop = (SceneObjectDragDropData)DragDrop.Data; OnDropSceneObject(currentWindowPos, sceneDragDrop.Objects); } } isDragInBounds = false; } } /// /// Destroy the drop target. You should call this when done with the drop target. /// public void Destroy() { dropTargetOS.Destroy(); dropTargetOS = null; } /// /// Triggered when an OS drag event has entered the drop target area. /// /// X coordinate of the pointer relative to the parent window. /// Y coordinate of the pointer relative to the parent window. private void DoOnOSDragEnter(int x, int y) { isOSDragActive = true; if (OnEnter != null) OnEnter(new Vector2I(x, y)); } /// /// Triggered when an OS drag event has left the parent window. /// private void DoOnOSDragLeave() { isOSDragActive = false; if (OnLeave != null) OnLeave(); } /// /// Triggered when a pointer moves while an OS drag event is occuring over the drop target area. /// /// X coordinate of the pointer relative to the parent window. /// Y coordinate of the pointer relative to the parent window. private void DoOnOSDrag(int x, int y) { if (OnDrag != null) OnDrag(new Vector2I(x, y)); } /// /// Triggered when the pointer was released during an OS drag and drop operation while over the drop target area. /// /// X coordinate of the pointer relative to the parent window. /// Y coordinate of the pointer relative to the parent window. private void DoOnOSDrop(int x, int y) { isOSDragActive = false; if (OnDropResource != null) OnDropResource(new Vector2I(x, y), dropTargetOS.FilePaths); } } /** @} */ }