浏览代码

[Feature] Add Drag and Drop feature between UnityObject and UIWidgets

/main
iizzaya 5 年前
当前提交
4f3274d0
共有 14 个文件被更改,包括 695 次插入34 次删除
  1. 24
      Runtime/editor/editor_window.cs
  2. 10
      Runtime/gestures/binding.cs
  3. 25
      Runtime/gestures/converter.cs
  4. 123
      Runtime/gestures/events.cs
  5. 98
      Runtime/gestures/mouse_tracking.cs
  6. 98
      Runtime/rendering/proxy_box.cs
  7. 4
      Runtime/ui/pointer.cs
  8. 40
      Runtime/widgets/basic.cs
  9. 189
      Runtime/editor/editor_mouse_tracking.cs
  10. 11
      Runtime/editor/editor_mouse_tracking.cs.meta
  11. 8
      Runtime/editor/widgets.meta
  12. 88
      Runtime/editor/widgets/unity_object_detector.cs
  13. 11
      Runtime/editor/widgets/unity_object_detector.cs.meta

24
Runtime/editor/editor_window.cs


protected float deltaTime;
protected float unscaledDeltaTime;
void updatePhysicalSize() {
var size = this.queryWindowSize();
this._physicalSize = new Size(

public void onViewMetricsChanged() {
this._viewMetricsChanged = true;
}
protected abstract bool hasFocus();
public void OnEnable() {

evt.mousePosition.x * this._devicePixelRatio,
evt.mousePosition.y * this._devicePixelRatio,
evt.button
);
}
else if (evt.type == EventType.DragUpdated) {
pointerData = new PointerData(
timeStamp: Timer.timespanSinceStartup,
change: PointerChange.dragFromEditorMove,
kind: PointerDeviceKind.mouse,
device: evt.button,
physicalX: evt.mousePosition.x * this._devicePixelRatio,
physicalY: evt.mousePosition.y * this._devicePixelRatio
);
}
else if (evt.type == EventType.DragPerform) {
pointerData = new PointerData(
timeStamp: Timer.timespanSinceStartup,
change: PointerChange.dragFromEditorRelease,
kind: PointerDeviceKind.mouse,
device: evt.button,
physicalX: evt.mousePosition.x * this._devicePixelRatio,
physicalY: evt.mousePosition.y * this._devicePixelRatio
);
}

10
Runtime/gestures/binding.cs


if (hitTestResult != null ||
evt is PointerHoverEvent ||
evt is PointerAddedEvent ||
evt is PointerRemovedEvent
evt is PointerRemovedEvent ||
evt is PointerDragFromEditorHoverEvent ||
evt is PointerDragFromEditorReleaseEvent
) {
this.dispatchEvent(evt, hitTestResult);
}

public void dispatchEvent(PointerEvent evt, HitTestResult hitTestResult) {
if (hitTestResult == null) {
D.assert(evt is PointerHoverEvent || evt is PointerAddedEvent || evt is PointerRemovedEvent);
D.assert(evt is PointerHoverEvent ||
evt is PointerAddedEvent ||
evt is PointerRemovedEvent ||
evt is PointerDragFromEditorHoverEvent ||
evt is PointerDragFromEditorReleaseEvent);
try {
this.pointerRouter.route(evt);
}

25
Runtime/gestures/converter.cs


if (state.down) {
break;
}
if (state.lastPosition != position) {
// a hover event to be here.
state.lastPosition = position;

position: position
);
}
}
break;
case PointerChange.dragFromEditorMove: {
_PointerState state = _ensureStateForPointer(datum, position);
state.startNewPointer();
yield return new PointerDragFromEditorHoverEvent(
timeStamp: timeStamp,
pointer: state.pointer,
kind: kind,
device: datum.device,
position: position
);
}
break;
case PointerChange.dragFromEditorRelease: {
_PointerState state = _ensureStateForPointer(datum, position);
state.startNewPointer();
yield return new PointerDragFromEditorReleaseEvent(
timeStamp: timeStamp,
pointer: state.pointer,
kind: kind,
device: datum.device,
position: position
);
}
break;
}

123
Runtime/gestures/events.cs


using System;
using Unity.UIWidgets.ui;
using Object = UnityEngine.Object;
namespace Unity.UIWidgets.gestures {
public abstract class PointerEvent {

delta: delta) {
}
}
public class PointerDragFromEditorEnterEvent : PointerEvent {
public PointerDragFromEditorEnterEvent(
TimeSpan timeStamp,
int pointer = 0,
PointerDeviceKind kind = PointerDeviceKind.mouse,
int device = 0,
Offset position = null
) : base(
timeStamp,
pointer: pointer,
kind: kind,
device: device,
position: position
) { }
public static PointerDragFromEditorEnterEvent fromDragFromEditorEvent(PointerEvent evt) {
return new PointerDragFromEditorEnterEvent(
timeStamp: evt.timeStamp,
pointer: evt.pointer,
kind: evt.kind,
device: evt.device,
position: evt.position
);
}
}
public class PointerDragFromEditorExitEvent : PointerEvent {
public PointerDragFromEditorExitEvent(
TimeSpan timeStamp,
int pointer = 0,
PointerDeviceKind kind = PointerDeviceKind.mouse,
int device = 0,
Offset position = null
) : base(
timeStamp,
pointer: pointer,
kind: kind,
device: device,
position: position
) { }
public static PointerDragFromEditorExitEvent fromDragFromEditorEvent(PointerEvent evt) {
return new PointerDragFromEditorExitEvent(
timeStamp: evt.timeStamp,
pointer: evt.pointer,
kind: evt.kind,
device: evt.device,
position: evt.position
);
}
}
public class PointerDragFromEditorHoverEvent : PointerEvent {
public PointerDragFromEditorHoverEvent(
TimeSpan timeStamp,
int pointer = 0,
PointerDeviceKind kind = PointerDeviceKind.mouse,
int device = 0,
Offset position = null
) : base(
timeStamp,
pointer: pointer,
kind: kind,
device: device,
position: position
) { }
public static PointerDragFromEditorHoverEvent fromDragFromEditorEvent(PointerEvent evt) {
return new PointerDragFromEditorHoverEvent(
timeStamp: evt.timeStamp,
pointer: evt.pointer,
kind: evt.kind,
device: evt.device,
position: evt.position
);
}
}
public class PointerDragFromEditorReleaseEvent : PointerEvent {
public PointerDragFromEditorReleaseEvent(
TimeSpan timeStamp,
int pointer = 0,
PointerDeviceKind kind = PointerDeviceKind.mouse,
int device = 0,
Offset position = null,
Object[] objectReferences = null
) : base(
timeStamp,
pointer: pointer,
kind: kind,
device: device,
position: position
) {
this.objectReferences = objectReferences;
}
public Object[] objectReferences;
public static PointerDragFromEditorReleaseEvent fromDragFromEditorEvent(PointerEvent evt, Object[] objectReferences) {
return new PointerDragFromEditorReleaseEvent(
timeStamp: evt.timeStamp,
pointer: evt.pointer,
kind: evt.kind,
device: evt.device,
position: evt.position,
objectReferences: objectReferences
);
}
}
public class PointerDragFromEditorFailedEvent : PointerEvent {
public PointerDragFromEditorFailedEvent(
TimeSpan timeStamp,
int pointer = 0,
PointerDeviceKind kind = PointerDeviceKind.mouse,
int device = 0,
Offset position = null
) : base(
timeStamp,
pointer: pointer,
kind: kind,
device: device,
position: position
) { }
}
public class PointerHoverEvent : PointerEvent {
public PointerHoverEvent(

98
Runtime/gestures/mouse_tracking.cs


using Unity.UIWidgets.ui;
namespace Unity.UIWidgets.gestures {
#if UNITY_EDITOR
public delegate void PointerDragFromEditorEnterEventListener(PointerDragFromEditorEnterEvent evt);
public delegate void PointerDragFromEditorHoverEventListener(PointerDragFromEditorHoverEvent evt);
public delegate void PointerDragFromEditorExitEventListener(PointerDragFromEditorExitEvent evt);
public delegate void PointerDragFromEditorReleaseEventListener(PointerDragFromEditorReleaseEvent evt);
#endif
/// The annotation object used to annotate layers that are interested in mouse
/// movements.
/// This is added to a layer and managed by the [Listener] widget.
PointerExitEventListener onExit = null
PointerExitEventListener onExit = null,
PointerDragFromEditorEnterEventListener onDragFromEditorEnter = null,
PointerDragFromEditorHoverEventListener onDragFromEditorHover = null,
PointerDragFromEditorExitEventListener onDragFromEditorExit = null,
PointerDragFromEditorReleaseEventListener onDragFromEditorRelease = null
this.onDragFromEditorEnter = onDragFromEditorEnter;
this.onDragFromEditorHover = onDragFromEditorHover;
this.onDragFromEditorExit = onDragFromEditorExit;
this.onDragFromEditorRelease = onDragFromEditorRelease;
}
public readonly PointerEnterEventListener onEnter;

public readonly PointerExitEventListener onExit;
public readonly PointerDragFromEditorEnterEventListener onDragFromEditorEnter;
public readonly PointerDragFromEditorHoverEventListener onDragFromEditorHover;
public readonly PointerDragFromEditorExitEventListener onDragFromEditorExit;
public readonly PointerDragFromEditorReleaseEventListener onDragFromEditorRelease;
return $"{this.GetType()}#{this.GetHashCode()}{(this.onEnter == null ? "" : " onEnter")}{(this.onHover == null ? "" : " onHover")}{(this.onExit == null ? "" : " onExit")}";
return
$"{this.GetType()}#{this.GetHashCode()}{(this.onEnter == null ? "" : " onEnter")}{(this.onHover == null ? "" : " onHover")}{(this.onExit == null ? "" : " onExit")}";
}
}

this.annotation = annotation;
}
public readonly MouseTrackerAnnotation annotation;
public HashSet<int> activeDevices = new HashSet<int>();

public class MouseTracker {
public partial class MouseTracker {
public MouseTracker(
PointerRouter router,
MouseDetectorAnnotationFinder annotationFinder) {

readonly Dictionary<int, PointerEvent> _lastMouseEvent = new Dictionary<int, PointerEvent>();
public bool mouseIsConnected {

public readonly Dictionary<MouseTrackerAnnotation, _TrackedAnnotation> _trackedAnnotations =
new Dictionary<MouseTrackerAnnotation, _TrackedAnnotation>();
#if UNITY_EDITOR
this._scheduleDragFromEditorMousePositionCheck();
#endif
annotation.onExit(PointerExitEvent.fromHoverEvent((PointerHoverEvent) this._lastMouseEvent[deviceId]));
if (annotation.onExit != null) {
annotation.onExit(
PointerExitEvent.fromHoverEvent((PointerHoverEvent) this._lastMouseEvent[deviceId]));
}
#if UNITY_EDITOR
if (annotation.onDragFromEditorExit != null) {
annotation.onDragFromEditorExit(
PointerDragFromEditorExitEvent.fromDragFromEditorEvent(this._lastMouseEvent[deviceId]));
#endif
}
}
this._trackedAnnotations.Remove(annotation);

SchedulerBinding.instance.addPostFrameCallback(_ => { this.collectMousePositions();});
SchedulerBinding.instance.addPostFrameCallback(_ => { this.collectMousePositions(); });
// Handler for events coming from the PointerRouter.
void _handleEvent(PointerEvent evt) {
if (evt.kind != PointerDeviceKind.mouse) {
return;

if (this._trackedAnnotations.isEmpty()) {
// If we are adding the device again, then we're not removing it anymore.
this._lastMouseEvent.Remove(deviceId);
return;
}

// If the mouse was removed, then we need to schedule one more check to
// exit any annotations that were active.
this._scheduleMousePositionCheck();
}
else {

this._lastMouseEvent[deviceId] = evt;
}
}
#if UNITY_EDITOR
this._handleDragFromEditorEvent(evt, deviceId);
#endif
"Check that attachAnnotation has been called for all annotated layers.");
"Check that attachAnnotation has been called for all annotated layers.");
/// Tells interested objects that a mouse has entered, exited, or moved, given
/// a callback to fetch the [MouseTrackerAnnotation] associated with a global
/// offset.
///
/// This is called from a post-frame callback when the layer tree has been
/// updated, right after rendering the frame.
///
/// This function is only public to allow for proper testing of the
/// MouseTracker. Do not call in other contexts.
if (trackedAnnotation.annotation?.onExit != null &&
trackedAnnotation.activeDevices.Contains(deviceId)) {
trackedAnnotation.annotation.onExit(PointerExitEvent.fromHoverEvent(this._lastMouseEvent[deviceId]));
if (trackedAnnotation.activeDevices.Contains(deviceId)) {
if (trackedAnnotation.annotation?.onExit != null) {
trackedAnnotation.annotation.onExit(
PointerExitEvent.fromHoverEvent(this._lastMouseEvent[deviceId]));
}
trackedAnnotation.activeDevices.Remove(deviceId);
}
}

if (hitAnnotation.annotation?.onHover != null) {
hitAnnotation.annotation.onHover(PointerHoverEvent.fromHoverEvent(lastEvent));
}
//leave
foreach (_TrackedAnnotation trackedAnnotation in this._trackedAnnotations.Values) {
if (hitAnnotation == trackedAnnotation) {

if (trackedAnnotation.activeDevices.Contains(deviceId)) {
if (trackedAnnotation.annotation?.onExit != null) {
trackedAnnotation.annotation.onExit(PointerExitEvent.fromHoverEvent((PointerHoverEvent)lastEvent));
trackedAnnotation.annotation.onExit(
PointerExitEvent.fromHoverEvent((PointerHoverEvent) lastEvent));
}
trackedAnnotation.activeDevices.Remove(deviceId);

98
Runtime/rendering/proxy_box.cs


PointerCancelEventListener onPointerCancel = null,
PointerScrollEventListener onPointerScroll = null,
HitTestBehavior behavior = HitTestBehavior.deferToChild,
RenderBox child = null
RenderBox child = null,
// Drag & Drop
PointerDragFromEditorEnterEventListener onPointerDragFromEditorEnter = null,
PointerDragFromEditorHoverEventListener onPointerDragFromEditorHover = null,
PointerDragFromEditorExitEventListener onPointerDragFromEditorExit = null,
PointerDragFromEditorReleaseEventListener onPointerDragFromEditorRelease = null
) : base(behavior: behavior, child: child) {
this.onPointerDown = onPointerDown;
this.onPointerMove = onPointerMove;

this._onPointerHover = onPointerHover;
this._onPointerExit = onPointerExit;
if (this._onPointerEnter != null || this._onPointerHover != null || this._onPointerExit != null) {
// Drag & Drop
this._onPointerDragFromEditorEnter = onPointerDragFromEditorEnter;
this._onPointerDragFromEditorHover = onPointerDragFromEditorHover;
this._onPointerDragFromEditorExit = onPointerDragFromEditorExit;
this._onPointerDragFromEditorRelease = onPointerDragFromEditorRelease;
if (this._onPointerEnter != null ||
this._onPointerHover != null ||
this._onPointerExit != null ||
this._onPointerDragFromEditorEnter != null ||
this._onPointerDragFromEditorHover != null ||
this._onPointerDragFromEditorExit != null ||
this._onPointerDragFromEditorRelease != null) {
onExit: this._onPointerExit);
onExit: this._onPointerExit,
onDragFromEditorEnter: this._onPointerDragFromEditorEnter,
onDragFromEditorHover: this._onPointerDragFromEditorHover,
onDragFromEditorExit: this._onPointerDragFromEditorExit,
onDragFromEditorRelease: this._onPointerDragFromEditorRelease
);
}
}

PointerDragFromEditorEnterEventListener _onPointerDragFromEditorEnter;
public PointerDragFromEditorEnterEventListener onPointerDragFromEditorEnter {
get { return this._onPointerDragFromEditorEnter; }
set {
if (this._onPointerDragFromEditorEnter != value) {
this._onPointerDragFromEditorEnter = value;
this._updateAnnotations();
}
}
}
PointerDragFromEditorExitEventListener _onPointerDragFromEditorExit;
public PointerDragFromEditorExitEventListener onPointerDragFromEditorExit {
get { return this._onPointerDragFromEditorExit; }
set {
if (this._onPointerDragFromEditorExit != value) {
this._onPointerDragFromEditorExit = value;
this._updateAnnotations();
}
}
}
PointerDragFromEditorHoverEventListener _onPointerDragFromEditorHover;
public PointerDragFromEditorHoverEventListener onPointerDragFromEditorHover {
get { return this._onPointerDragFromEditorHover; }
set {
if (this._onPointerDragFromEditorHover != value) {
this._onPointerDragFromEditorHover = value;
this._updateAnnotations();
}
}
}
PointerDragFromEditorReleaseEventListener _onPointerDragFromEditorRelease;
public PointerDragFromEditorReleaseEventListener onPointerDragFromEditorRelease {
get { return this._onPointerDragFromEditorRelease; }
set {
if (this._onPointerDragFromEditorRelease != value) {
this._onPointerDragFromEditorRelease = value;
this._updateAnnotations();
}
}
}
public PointerEnterEventListener onPointerEnter {
get { return this._onPointerEnter; }
set {

void _updateAnnotations() {
D.assert(this._onPointerEnter != this._hoverAnnotation.onEnter ||
this._onPointerHover != this._hoverAnnotation.onHover ||
this._onPointerExit != this._hoverAnnotation.onExit,
this._onPointerExit != this._hoverAnnotation.onExit ||
this._onPointerDragFromEditorEnter != this._hoverAnnotation.onDragFromEditorEnter ||
this._onPointerDragFromEditorHover != this._hoverAnnotation.onDragFromEditorHover ||
this._onPointerDragFromEditorExit != this._hoverAnnotation.onDragFromEditorExit ||
this._onPointerDragFromEditorRelease != this._hoverAnnotation.onDragFromEditorRelease,
() => "Shouldn't call _updateAnnotations if nothing has changed.");
if (this._hoverAnnotation != null && this.attached) {

if (this._onPointerEnter != null || this._onPointerHover != null || this._onPointerExit != null) {
if (this._onPointerEnter != null ||
this._onPointerHover != null ||
this._onPointerExit != null ||
this._onPointerDragFromEditorEnter != null ||
this._onPointerDragFromEditorHover != null ||
this._onPointerDragFromEditorExit != null ||
this._onPointerDragFromEditorRelease != null) {
onExit: this._onPointerExit);
onExit: this._onPointerExit,
onDragFromEditorEnter: this._onPointerDragFromEditorEnter,
onDragFromEditorHover: this._onPointerDragFromEditorHover,
onDragFromEditorExit: this._onPointerDragFromEditorExit,
onDragFromEditorRelease: this._onPointerDragFromEditorRelease
);
if (this.attached) {
RendererBinding.instance.mouseTracker.attachAnnotation(this._hoverAnnotation);

4
Runtime/ui/pointer.cs


down,
move,
up,
scroll
scroll,
dragFromEditorMove, // Drag & Drop
dragFromEditorRelease
}
public enum PointerDeviceKind {

40
Runtime/widgets/basic.cs


PointerCancelEventListener onPointerCancel = null,
PointerScrollEventListener onPointerScroll = null,
HitTestBehavior behavior = HitTestBehavior.deferToChild,
Widget child = null
Widget child = null,
// Drag & Drop
PointerDragFromEditorEnterEventListener onPointerDragFromEditorEnter = null,
PointerDragFromEditorHoverEventListener onPointerDragFromEditorHover = null,
PointerDragFromEditorExitEventListener onPointerDragFromEditorExit = null,
PointerDragFromEditorReleaseEventListener onPointerDragFromEditorRelease = null
) : base(key: key, child: child) {
this.onPointerDown = onPointerDown;
this.onPointerMove = onPointerMove;

this.onPointerEnter = onPointerEnter;
this.onPointerScroll = onPointerScroll;
this.behavior = behavior;
// Drag & Drop
this.onPointerDragFromEditorEnter = onPointerDragFromEditorEnter;
this.onPointerDragFromEditorHover = onPointerDragFromEditorHover;
this.onPointerDragFromEditorExit = onPointerDragFromEditorExit;
this.onPointerDragFromEditorRelease = onPointerDragFromEditorRelease;
}
public readonly PointerDownEventListener onPointerDown;

public readonly PointerScrollEventListener onPointerScroll;
public readonly HitTestBehavior behavior;
// Drag & Drop
public readonly PointerDragFromEditorEnterEventListener onPointerDragFromEditorEnter;
public readonly PointerDragFromEditorHoverEventListener onPointerDragFromEditorHover;
public readonly PointerDragFromEditorExitEventListener onPointerDragFromEditorExit;
public readonly PointerDragFromEditorReleaseEventListener onPointerDragFromEditorRelease;
public override RenderObject createRenderObject(BuildContext context) {
return new RenderPointerListener(

onPointerExit: this.onPointerExit,
onPointerHover: this.onPointerHover,
onPointerScroll: this.onPointerScroll,
behavior: this.behavior
behavior: this.behavior,
// Drag & Drop
onPointerDragFromEditorEnter: this.onPointerDragFromEditorEnter,
onPointerDragFromEditorHover: this.onPointerDragFromEditorHover,
onPointerDragFromEditorExit: this.onPointerDragFromEditorExit,
onPointerDragFromEditorRelease: this.onPointerDragFromEditorRelease
);
}

renderObject.onPointerExit = this.onPointerExit;
renderObject.onPointerScroll = this.onPointerScroll;
renderObject.behavior = this.behavior;
// Drag & Drop
renderObject.onPointerDragFromEditorEnter = this.onPointerDragFromEditorEnter;
renderObject.onPointerDragFromEditorHover = this.onPointerDragFromEditorHover;
renderObject.onPointerDragFromEditorExit = this.onPointerDragFromEditorExit;
renderObject.onPointerDragFromEditorRelease = this.onPointerDragFromEditorRelease;
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {

if (this.onPointerScroll != null) {
listeners.Add("scroll");
}
// Drag & Drop
if (this.onPointerDragFromEditorEnter != null) listeners.Add("dragFromEditorEnter");
if (this.onPointerDragFromEditorHover != null) listeners.Add("dragFromEditorHover");
if (this.onPointerDragFromEditorExit != null) listeners.Add("dragFromEditorExit");
if (this.onPointerDragFromEditorRelease != null) listeners.Add("dragFromEditorRelease");
properties.add(new EnumerableProperty<string>("listeners", listeners, ifEmpty: "<none>"));
properties.add(new EnumProperty<HitTestBehavior>("behavior", this.behavior));

189
Runtime/editor/editor_mouse_tracking.cs


using System.Collections.Generic;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.scheduler;
using UnityEditor;
namespace Unity.UIWidgets.gestures {
public partial class MouseTracker {
bool _enableDragFromEditorRelease = false;
void _handleDragFromEditorEvent(PointerEvent evt, int deviceId) {
if (evt is PointerDragFromEditorReleaseEvent) {
this._enableDragFromEditorRelease = false;
this._scheduleDragFromEditorReleaseCheck();
this._lastMouseEvent.Remove(deviceId);
}
else if (evt is PointerDragFromEditorEnterEvent ||
evt is PointerDragFromEditorHoverEvent ||
evt is PointerDragFromEditorExitEvent) {
if (!this._lastMouseEvent.ContainsKey(deviceId) ||
this._lastMouseEvent[deviceId].position != evt.position) {
// Only schedule a frame if we have our first event, or if the
// location of the mouse has changed, and only if there are tracked annotations.
this._scheduleDragFromEditorMousePositionCheck();
}
this._lastMouseEvent[deviceId] = evt;
}
}
void _scheduleDragFromEditorReleaseCheck() {
DragAndDrop.AcceptDrag();
var lastMouseEvent = new List<(PointerEvent, int)>();
foreach (int deviceId in this._lastMouseEvent.Keys) {
lastMouseEvent.Add((this._lastMouseEvent[deviceId], deviceId));
}
SchedulerBinding.instance.addPostFrameCallback(_ => {
foreach (var lastEvent in lastMouseEvent) {
MouseTrackerAnnotation hit = this.annotationFinder(lastEvent.Item1.position);
if (hit == null) {
foreach (_TrackedAnnotation trackedAnnotation in this._trackedAnnotations.Values) {
if (trackedAnnotation.activeDevices.Contains(lastEvent.Item2)) {
trackedAnnotation.activeDevices.Remove(lastEvent.Item2);
}
}
return;
}
_TrackedAnnotation hitAnnotation = this._findAnnotation(hit);
// release
if (hitAnnotation.activeDevices.Contains(lastEvent.Item2)) {
if (hitAnnotation.annotation?.onDragFromEditorRelease != null) {
hitAnnotation.annotation.onDragFromEditorRelease(
PointerDragFromEditorReleaseEvent
.fromDragFromEditorEvent(
lastEvent.Item1, DragAndDrop.objectReferences));
}
hitAnnotation.activeDevices.Remove(lastEvent.Item2);
}
}
});
SchedulerBinding.instance.scheduleFrame();
}
/// <summary>
/// Due to the [DragAndDrop] property, DragAndDrop.visualMode must be set to Copy
/// after which editor window can trigger DragPerform event.
/// And because visualMode will be set to None when every frame finished in IMGUI,
/// here we start a scheduler to update VisualMode in every post frame.
/// When [_enableDragFromEditorRelease] set to false, it will stop, vice versa.
/// </summary>
void _enableDragFromEditorReleaseVisualModeLoop() {
if (this._enableDragFromEditorRelease) {
DragAndDrop.visualMode = DragAndDropVisualMode.Copy;
SchedulerBinding.instance.addPostFrameCallback(_ => {
this._enableDragFromEditorReleaseVisualModeLoop();
});
SchedulerBinding.instance.scheduleFrame();
}
}
void _scheduleDragFromEditorMousePositionCheck() {
SchedulerBinding.instance.addPostFrameCallback(_ => { this.collectDragFromEditorMousePositions(); });
SchedulerBinding.instance.scheduleFrame();
}
public void collectDragFromEditorMousePositions() {
void exitAnnotation(_TrackedAnnotation trackedAnnotation, int deviceId) {
if (trackedAnnotation.activeDevices.Contains(deviceId)) {
this._enableDragFromEditorRelease = false;
if (trackedAnnotation.annotation?.onDragFromEditorExit != null) {
trackedAnnotation.annotation.onDragFromEditorExit(
PointerDragFromEditorExitEvent.fromDragFromEditorEvent(
this._lastMouseEvent[deviceId]));
}
trackedAnnotation.activeDevices.Remove(deviceId);
}
}
void exitAllDevices(_TrackedAnnotation trackedAnnotation) {
if (trackedAnnotation.activeDevices.isNotEmpty()) {
HashSet<int> deviceIds = new HashSet<int>(trackedAnnotation.activeDevices);
foreach (int deviceId in deviceIds) {
exitAnnotation(trackedAnnotation, deviceId);
}
}
}
if (!this.mouseIsConnected) {
foreach (var annotation in this._trackedAnnotations.Values) {
exitAllDevices(annotation);
}
return;
}
foreach (int deviceId in this._lastMouseEvent.Keys) {
PointerEvent lastEvent = this._lastMouseEvent[deviceId];
MouseTrackerAnnotation hit = this.annotationFinder(lastEvent.position);
if (hit == null) {
foreach (_TrackedAnnotation trackedAnnotation in this._trackedAnnotations.Values) {
exitAnnotation(trackedAnnotation, deviceId);
}
return;
}
_TrackedAnnotation hitAnnotation = this._findAnnotation(hit);
// While acrossing two areas, set the flag to true to prevent setting the Pointer Copy VisualMode to None
bool enterFlag = false;
// enter
if (!hitAnnotation.activeDevices.Contains(deviceId)) {
hitAnnotation.activeDevices.Add(deviceId);
enterFlag = true;
// Both onRelease or onEnter event will enable Copy VisualMode
if (hitAnnotation.annotation?.onDragFromEditorRelease != null ||
hitAnnotation.annotation?.onDragFromEditorEnter != null) {
if (!this._enableDragFromEditorRelease) {
this._enableDragFromEditorRelease = true;
this._enableDragFromEditorReleaseVisualModeLoop();
}
if (hitAnnotation.annotation?.onDragFromEditorEnter != null) {
hitAnnotation.annotation.onDragFromEditorEnter(
PointerDragFromEditorEnterEvent
.fromDragFromEditorEvent(lastEvent));
}
}
}
// hover
if (hitAnnotation.annotation?.onDragFromEditorHover != null) {
hitAnnotation.annotation.onDragFromEditorHover(
PointerDragFromEditorHoverEvent.fromDragFromEditorEvent(lastEvent));
}
// leave
foreach (_TrackedAnnotation trackedAnnotation in this._trackedAnnotations.Values) {
if (hitAnnotation == trackedAnnotation) {
continue;
}
if (trackedAnnotation.activeDevices.Contains(deviceId)) {
if (!enterFlag) {
this._enableDragFromEditorRelease = false;
}
if (trackedAnnotation.annotation?.onDragFromEditorExit != null) {
trackedAnnotation.annotation.onDragFromEditorExit(
PointerDragFromEditorExitEvent
.fromDragFromEditorEvent(lastEvent));
}
trackedAnnotation.activeDevices.Remove(deviceId);
}
}
}
}
}
}

11
Runtime/editor/editor_mouse_tracking.cs.meta


fileFormatVersion: 2
guid: 08df36a525b2c486aaf1c342786f08db
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

8
Runtime/editor/widgets.meta


fileFormatVersion: 2
guid: d5417058cad6148859c8ffde0f0f054b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

88
Runtime/editor/widgets/unity_object_detector.cs


using System;
using System.Collections.Generic;
using System.Linq;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.widgets;
using UnityEngine;
using Object = UnityEngine.Object;
namespace Unity.UIWidgets.editor {
public delegate void DragFromEditorEnterCallback();
public delegate void DragFromEditorHoverCallback();
public delegate void DragFromEditorExitCallback();
public delegate void DragFromEditorReleaseCallback(DragFromEditorDetails details);
public class DragFromEditorDetails {
public DragFromEditorDetails(Object[] objectReferences) {
this.objectReferences = objectReferences;
}
public readonly Object[] objectReferences;
}
public class UnityObjectDetector : StatefulWidget {
public UnityObjectDetector(
Key key = null,
Widget child = null,
DragFromEditorEnterCallback onEnter = null,
DragFromEditorHoverCallback onHover = null,
DragFromEditorExitCallback onExit = null,
DragFromEditorReleaseCallback onRelease = null,
HitTestBehavior? behavior = null
) : base(key: key) {
this.child = child;
this.onDragFromEditorEnter = onEnter;
this.onDragFromEditorHover = onHover;
this.onDragFromEditorExit = onExit;
this.onDragFromEditorRelease = onRelease;
this.behavior = behavior;
}
public readonly Widget child;
public readonly DragFromEditorEnterCallback onDragFromEditorEnter;
public readonly DragFromEditorHoverCallback onDragFromEditorHover;
public readonly DragFromEditorExitCallback onDragFromEditorExit;
public readonly DragFromEditorReleaseCallback onDragFromEditorRelease;
public readonly HitTestBehavior? behavior;
public override State createState() {
return new UnityObjectDetectorState();
}
}
public class UnityObjectDetectorState : State<UnityObjectDetector> {
HitTestBehavior _defaultBehavior {
get { return this.widget.child == null ? HitTestBehavior.translucent : HitTestBehavior.deferToChild; }
}
public override Widget build(BuildContext context) {
Widget result = new Listener(
child: this.widget.child,
onPointerDragFromEditorEnter: this.widget.onDragFromEditorEnter == null
? ((PointerDragFromEditorEnterEventListener) null)
: (evt) => { this.widget.onDragFromEditorEnter.Invoke(); },
onPointerDragFromEditorHover: this.widget.onDragFromEditorHover == null
? ((PointerDragFromEditorHoverEventListener) null)
: (evt) => { this.widget.onDragFromEditorHover.Invoke(); },
onPointerDragFromEditorExit: this.widget.onDragFromEditorExit == null
? ((PointerDragFromEditorExitEventListener) null)
: (evt) => { this.widget.onDragFromEditorExit.Invoke(); },
onPointerDragFromEditorRelease: this.widget.onDragFromEditorRelease == null
? ((PointerDragFromEditorReleaseEventListener) null)
: (evt) => {
this.widget.onDragFromEditorRelease.Invoke(new DragFromEditorDetails(evt.objectReferences));
},
behavior: this.widget.behavior ?? this._defaultBehavior
);
return result;
}
}
}

11
Runtime/editor/widgets/unity_object_detector.cs.meta


fileFormatVersion: 2
guid: 899c58f21c1724297b48da615ccb7088
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
正在加载...
取消
保存