浏览代码

Merge pull request #253 from IIzzaya/drag_and_drop

[Feature] Add Drag and Drop feature between UnityObject and UIWidgets
/main
GitHub 5 年前
当前提交
8664527c
共有 24 个文件被更改,包括 1341 次插入46 次删除
  1. 10
      README-ZH.md
  2. 10
      README.md
  3. 34
      Runtime/editor/editor_window.cs
  4. 11
      Runtime/gestures/binding.cs
  5. 27
      Runtime/gestures/converter.cs
  6. 120
      Runtime/gestures/events.cs
  7. 103
      Runtime/gestures/mouse_tracking.cs
  8. 13
      Runtime/rendering/binding.cs
  9. 109
      Runtime/rendering/proxy_box.cs
  10. 4
      Runtime/ui/pointer.cs
  11. 46
      Runtime/widgets/basic.cs
  12. 2
      Runtime/widgets/binding.cs
  13. 210
      Runtime/editor/editor_mouse_tracking.cs
  14. 11
      Runtime/editor/editor_mouse_tracking.cs.meta
  15. 8
      Runtime/editor/widgets.meta
  16. 8
      Samples/UIWidgetSample/DragNDrop.meta
  17. 11
      Runtime/editor/widgets/unity_object_detector.cs.meta
  18. 83
      Runtime/editor/widgets/unity_object_detector.cs
  19. 171
      Samples/UIWidgetSample/DragNDrop/UnityObjectDetectorSample.cs
  20. 11
      Samples/UIWidgetSample/DragNDrop/UnityObjectDetectorSample.cs.meta
  21. 11
      Samples/UIWidgetSample/DragNDrop/CustomInspectorSample.cs.meta
  22. 374
      Samples/UIWidgetSample/DragNDrop/CustomInspectorSample.cs

10
README-ZH.md


如果您希望使用自己的表情图片,请更新纹理图`Tests/Resources/Emoji.png`,以及`Runtime/ui/txt/emoji.cs`中将Unicode映射到纹理图中具体位置的映射表。
特别地,请记得更新Dictionary变量`emojiLookupTable`,纹理图的行数`rowCount`以及纹理图的列数`colCount`。
#### 十一、与GameObject进行拖拽交互
<div style="text-align: center">
<img src="https://connect-prd-cdn.unity.com/20190718/p/images/e3c9cf9b-c732-4eb2-9afd-fe7de894f342_Custom_Inspector_Showcase_320px.gif" width="300"/>
</div>
我们提供了一个包装好的`UnityObjectDetector`组件以及`onRelease`回调函数,借此您可以实现简单地将物体(例如Hierarchy内的场景物体、Project窗口下的文件等)拖拽至区域内,来获得`UnityEngine.Object[] `类型的引用并进行操作。
你可以在“UIWidgetsTests -> Drag&Drop”下找到简单的实例样例。
## 调试UIWidgets应用程序

10
README.md


in the texture. Specifically, remember to update the Dictionary `emojiLookupTable`, number of rows
in the texture `rowCount`, and number of columns `colCount`.
#### Interact with GameObject Drag&Drops
<div style="text-align: center">
<img src="https://connect-prd-cdn.unity.com/20190718/p/images/e3c9cf9b-c732-4eb2-9afd-fe7de894f342_Custom_Inspector_Showcase_320px.gif" width="300"/>
</div>
With the provided packaged stateful widget `UnityObjectDetector` and its `onRelease` callback function, you can easily drag some objects (for example GameObject from Hierarchy, files from Project Window, etc) into the area, get the UnityEngine.Object[] references and make further modification.
Please refer to "UIWidgetsTests -> Drag&Drop" for simple examples.
## Debug UIWidgets Application

34
Runtime/editor/editor_window.cs


public class EditorWindowAdapter : WindowAdapter {
public readonly EditorWindow editorWindow;
public EditorWindowAdapter(EditorWindow editorWindow) {
public EditorWindowAdapter(EditorWindow editorWindow) : base(true) {
this.editorWindow = editorWindow;
}

public abstract class WindowAdapter : Window {
static readonly List<WindowAdapter> _windowAdapters = new List<WindowAdapter>();
public WindowAdapter(bool inEditorWindow = false) {
this.inEditorWindow = inEditorWindow;
}
public static List<WindowAdapter> windowAdapters {
get { return _windowAdapters; }
}

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() {

this._surface = null;
}
readonly protected bool inEditorWindow;
this._binding = new WidgetsBinding();
this._binding = new WidgetsBinding(this.inEditorWindow);
}
SchedulerBinding._instance = this._binding;

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
);
}

11
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);
}

27
Runtime/gestures/converter.cs


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

}
}
break;
#if UNITY_EDITOR
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;
#endif
}
}
}

120
Runtime/gestures/events.cs


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

}
}
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 PointerHoverEvent : PointerEvent {
public PointerHoverEvent(

position: position,
down: false) {
}
public static PointerHoverEvent fromHoverEvent(PointerEvent hover) {
return new PointerHoverEvent(
timeStamp: hover.timeStamp,

kind: hover.kind,
device: hover.device,
position: hover.position
);
);
}
}

position: position,
down: false) {
}
public static PointerExitEvent fromHoverEvent(PointerEvent hover) {
return new PointerExitEvent(
timeStamp: hover.timeStamp,

103
Runtime/gestures/mouse_tracking.cs


using Unity.UIWidgets.ui;
namespace Unity.UIWidgets.gestures {
public delegate void PointerDragFromEditorEnterEventListener(PointerDragFromEditorEnterEvent evt);
public delegate void PointerDragFromEditorHoverEventListener(PointerDragFromEditorHoverEvent evt);
public delegate void PointerDragFromEditorExitEventListener(PointerDragFromEditorExitEvent evt);
public delegate void PointerDragFromEditorReleaseEventListener(PointerDragFromEditorReleaseEvent evt);
/// 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 {
MouseDetectorAnnotationFinder annotationFinder) {
MouseDetectorAnnotationFinder annotationFinder,
bool inEditorWindow = false
) {
this.inEditorWindow = inEditorWindow;
readonly bool inEditorWindow;
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
this.detachDragFromEditorAnnotation(annotation, 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);
}
}

}
_TrackedAnnotation hitAnnotation = this._findAnnotation(hit);
//enter
if (!hitAnnotation.activeDevices.Contains(deviceId)) {
hitAnnotation.activeDevices.Add(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);

13
Runtime/rendering/binding.cs


set { PaintingBinding.instance = value; }
}
public RendererBinding() {
public RendererBinding(bool inEditorWindow = false) {
this._pipelineOwner = new PipelineOwner(
onNeedVisualUpdate: this.ensureVisualUpdate
);

this.initRenderView();
D.assert(this.renderView != null);
this.addPersistentFrameCallback(this._handlePersistentFrameCallback);
this.inEditorWindow = inEditorWindow;
this._mouseTracker = this._createMouseTracker();
}

public MouseTracker mouseTracker {
get { return this._mouseTracker; }
}
MouseTracker _mouseTracker;
public PipelineOwner pipelineOwner {

this.drawFrame();
}
readonly protected bool inEditorWindow;
offset
);
});
offset
);
}, this.inEditorWindow);
}
protected virtual void drawFrame() {

109
Runtime/rendering/proxy_box.cs


get { return Offset.zero & this.size; }
}
public override bool hitTest(HitTestResult result,
public override bool hitTest(HitTestResult result,
Offset position = null
) {
this._updateClip();

PointerUpEventListener onPointerUp = null,
PointerCancelEventListener onPointerCancel = null,
PointerScrollEventListener onPointerScroll = null,
PointerDragFromEditorEnterEventListener onPointerDragFromEditorEnter = null,
PointerDragFromEditorHoverEventListener onPointerDragFromEditorHover = null,
PointerDragFromEditorExitEventListener onPointerDragFromEditorExit = null,
PointerDragFromEditorReleaseEventListener onPointerDragFromEditorRelease = null,
HitTestBehavior behavior = HitTestBehavior.deferToChild,
RenderBox child = null
) : base(behavior: behavior, child: child) {

this._onPointerHover = onPointerHover;
this._onPointerExit = onPointerExit;
if (this._onPointerEnter != null || this._onPointerHover != null || this._onPointerExit != null) {
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();
}
public PointerDownEventListener onPointerDown;
PointerDragFromEditorReleaseEventListener _onPointerDragFromEditorRelease;
public PointerMoveEventListener onPointerMove;
public PointerDragFromEditorReleaseEventListener onPointerDragFromEditorRelease {
get { return this._onPointerDragFromEditorRelease; }
set {
if (this._onPointerDragFromEditorRelease != value) {
this._onPointerDragFromEditorRelease = value;
this._updateAnnotations();
}
}
}
public PointerEnterEventListener onPointerEnter {
get { return this._onPointerEnter; }

PointerExitEventListener _onPointerExit;
public PointerDownEventListener onPointerDown;
public PointerMoveEventListener onPointerMove;
public PointerUpEventListener onPointerUp;
public PointerCancelEventListener onPointerCancel;

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

4
Runtime/ui/pointer.cs


down,
move,
up,
scroll
scroll,
dragFromEditorMove,
dragFromEditorRelease
}
public enum PointerDeviceKind {

46
Runtime/widgets/basic.cs


PointerUpEventListener onPointerUp = null,
PointerCancelEventListener onPointerCancel = null,
PointerScrollEventListener onPointerScroll = null,
PointerDragFromEditorEnterEventListener onPointerDragFromEditorEnter = null,
PointerDragFromEditorHoverEventListener onPointerDragFromEditorHover = null,
PointerDragFromEditorExitEventListener onPointerDragFromEditorExit = null,
PointerDragFromEditorReleaseEventListener onPointerDragFromEditorRelease = null,
HitTestBehavior behavior = HitTestBehavior.deferToChild,
Widget child = null
) : base(key: key, child: child) {

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

public readonly HitTestBehavior behavior;
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(
onPointerDown: this.onPointerDown,

onPointerExit: this.onPointerExit,
onPointerHover: this.onPointerHover,
onPointerScroll: this.onPointerScroll,
onPointerDragFromEditorEnter: this.onPointerDragFromEditorEnter,
onPointerDragFromEditorHover: this.onPointerDragFromEditorHover,
onPointerDragFromEditorExit: this.onPointerDragFromEditorExit,
onPointerDragFromEditorRelease: this.onPointerDragFromEditorRelease,
behavior: this.behavior
);
}

renderObject.onPointerExit = this.onPointerExit;
renderObject.onPointerScroll = this.onPointerScroll;
renderObject.behavior = this.behavior;
#if UNITY_EDITOR
renderObject.onPointerDragFromEditorEnter = this.onPointerDragFromEditorEnter;
renderObject.onPointerDragFromEditorHover = this.onPointerDragFromEditorHover;
renderObject.onPointerDragFromEditorExit = this.onPointerDragFromEditorExit;
renderObject.onPointerDragFromEditorRelease = this.onPointerDragFromEditorRelease;
#endif
}
public override void debugFillProperties(DiagnosticPropertiesBuilder properties) {

if (this.onPointerScroll != null) {
listeners.Add("scroll");
}
#if UNITY_EDITOR
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");
}
#endif
properties.add(new EnumerableProperty<string>("listeners", listeners, ifEmpty: "<none>"));
properties.add(new EnumProperty<HitTestBehavior>("behavior", this.behavior));

2
Runtime/widgets/binding.cs


set { RendererBinding.instance = value; }
}
public WidgetsBinding() {
public WidgetsBinding(bool inEditorWindow = false) : base(inEditorWindow) {
this.buildOwner.onBuildScheduled = this._handleBuildScheduled;
Window.instance.onLocaleChanged += this.handleLocaleChanged;
this.widgetInspectorService = new WidgetInspectorService(this);

210
Runtime/editor/editor_mouse_tracking.cs


using System.Collections.Generic;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.scheduler;
using UnityEditor;
namespace Unity.UIWidgets.gestures {
#if UNITY_EDITOR
public partial class MouseTracker {
bool _enableDragFromEditorRelease = false;
void _handleDragFromEditorEvent(PointerEvent evt, int deviceId) {
if (!this.inEditorWindow) {
return;
}
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) {
this._scheduleDragFromEditorMousePositionCheck();
}
this._lastMouseEvent[deviceId] = evt;
}
}
void detachDragFromEditorAnnotation(MouseTrackerAnnotation annotation, int deviceId) {
if (!this.inEditorWindow) {
return;
}
if (annotation.onDragFromEditorExit != null) {
annotation.onDragFromEditorExit(
PointerDragFromEditorExitEvent.fromDragFromEditorEvent(this._lastMouseEvent[deviceId]));
}
}
void _scheduleDragFromEditorReleaseCheck() {
DragAndDrop.AcceptDrag();
var lastMouseEvent = new List<PointerEvent>();
foreach (int deviceId in this._lastMouseEvent.Keys) {
var _deviceId = deviceId;
lastMouseEvent.Add(this._lastMouseEvent[_deviceId]);
SchedulerBinding.instance.addPostFrameCallback(_ => {
foreach (var lastEvent in lastMouseEvent) {
MouseTrackerAnnotation hit = this.annotationFinder(lastEvent.position);
if (hit == null) {
foreach (_TrackedAnnotation trackedAnnotation in this._trackedAnnotations.Values) {
if (trackedAnnotation.activeDevices.Contains(_deviceId)) {
trackedAnnotation.activeDevices.Remove(_deviceId);
}
}
return;
}
_TrackedAnnotation hitAnnotation = this._findAnnotation(hit);
// release
if (hitAnnotation.activeDevices.Contains(_deviceId)) {
if (hitAnnotation.annotation?.onDragFromEditorRelease != null) {
hitAnnotation.annotation.onDragFromEditorRelease(
PointerDragFromEditorReleaseEvent
.fromDragFromEditorEvent(
lastEvent, DragAndDrop.objectReferences));
}
hitAnnotation.activeDevices.Remove(_deviceId);
}
}
});
}
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() {
if (!this.inEditorWindow) {
return;
}
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);
}
}
}
}
}
#endif
}

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:

8
Samples/UIWidgetSample/DragNDrop.meta


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

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:

83
Runtime/editor/widgets/unity_object_detector.cs


using Unity.UIWidgets.foundation;
using Unity.UIWidgets.gestures;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.widgets;
using UnityEngine;
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;
}
}
}

171
Samples/UIWidgetSample/DragNDrop/UnityObjectDetectorSample.cs


using System.Collections.Generic;
using Unity.UIWidgets.animation;
using Unity.UIWidgets.editor;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.material;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.widgets;
using UnityEditor;
using UnityEngine;
using Color = Unity.UIWidgets.ui.Color;
namespace UIWidgetsSample.DragNDrop {
public class UnityObjectDetectorSample : UIWidgetsEditorWindow {
[MenuItem("UIWidgetsTests/Drag&Drop/UnityObject Detector")]
public static void ShowEditorWindow() {
var window = GetWindow<UnityObjectDetectorSample>();
window.titleContent.text = "UnityObject Detector Sample";
}
protected override Widget createWidget() {
Debug.Log("[ WIDGET RECREATED ]");
return new WidgetsApp(
home: new UnityObjectDetectorSampleWidget(),
pageRouteBuilder: (RouteSettings settings, WidgetBuilder builder) =>
new PageRouteBuilder(
settings: settings,
pageBuilder: (BuildContext context, Animation<float> animation,
Animation<float> secondaryAnimation) => builder(context)
)
);
}
}
public class UnityObjectDetectorSampleWidget : StatefulWidget {
public UnityObjectDetectorSampleWidget(Key key = null) : base(key) {
}
public override State createState() {
return new UnityObjectDetectorSampleWidgetState();
}
}
public class UnityObjectDetectorSampleWidgetState : State<UnityObjectDetectorSampleWidget> {
readonly Color highlightColor = Color.fromARGB(255, 88, 127, 219);
readonly Color defaultColor = Color.fromARGB(255, 211, 211, 211);
readonly List<bool> isHighlighted = new List<bool> { };
readonly List<Object[]> objects = new List<Object[]>();
List<Widget> getUnityObjectDetectorList(int count) {
if (this.isHighlighted.isEmpty()) {
for (int i = 0; i < count; i++) {
this.isHighlighted.Add(false);
}
}
if (this.objects.isEmpty()) {
for (int i = 0; i < count; i++) {
this.objects.Add(null);
}
}
List<Widget> widgetList = new List<Widget>();
widgetList.Add(this.getGapBox("Generated List with UnityObjectDetector"));
for (int i = 0; i < count; i++) {
var _i = i;
Widget widget = new Container(
decoration: this.isHighlighted[_i]
? new BoxDecoration(color: this.highlightColor)
: new BoxDecoration(color: this.defaultColor),
height: 100f,
child: new UnityObjectDetector(
onEnter: () => {
Debug.Log("Widget " + _i + " onEnter");
this.setState(() => { this.isHighlighted[_i] = true; });
},
onRelease: (details) => {
Debug.Log("Widget " + _i + " onRelease");
this.setState(() => {
this.isHighlighted[_i] = false;
this.objects[_i] = details.objectReferences;
});
},
onExit: () => {
Debug.Log("Widget " + _i + " onExit");
this.setState(() => { this.isHighlighted[_i] = false; });
},
child: new Center(
child: new Text(this.objects[_i] != null
? this.getNameString(this.objects[_i])
: "[Drop/Multi-Drop Here]")
)
)
);
widgetList.Add(widget);
if (_i != count - 1) {
widgetList.Add(this.getGapBox());
}
}
return widgetList;
}
string getNameString(Object[] objs) {
var str = "";
for (int i = 0; i < objs.Length; i++) {
str += "[" + objs[i].name + "]";
if (i != objs.Length - 1) {
str += "\n";
}
}
return str;
}
Widget getGapBox(string str = "") {
return new Container(
height: 25,
child: str == ""
? null
: new Center(
child: new Text(str)
)
);
}
bool highlight;
Object[] objRef;
public override Widget build(BuildContext context) {
var columnList = new List<Widget>();
columnList.Add(this.getGapBox());
columnList.AddRange(this.getUnityObjectDetectorList(3));
columnList.AddRange(
new List<Widget> {
this.getGapBox("With Listener"),
new Container(
decoration: this.highlight
? new BoxDecoration(color: this.highlightColor)
: new BoxDecoration(color: this.defaultColor),
height: 100f,
child: new Listener(
onPointerDragFromEditorEnter: (evt) => { this.setState(() => { this.highlight = true; }); },
onPointerDragFromEditorExit: (evt) => { this.setState(() => { this.highlight = false; }); },
// onPointerDragFromEditorHover: (evt) => { },
onPointerDragFromEditorRelease: (evt) => {
this.objRef = evt.objectReferences;
this.setState(() => { this.highlight = false; });
},
child: new Center(
child: new Text(this.objRef != null
? this.getNameString(this.objRef)
: "[Drop/Multi-Drop Here]")
)
)
)
}
);
return new Container(
padding: EdgeInsets.symmetric(horizontal: 25f),
color: Colors.grey,
child: new ListView(
children: columnList
));
}
}
}

11
Samples/UIWidgetSample/DragNDrop/UnityObjectDetectorSample.cs.meta


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

11
Samples/UIWidgetSample/DragNDrop/CustomInspectorSample.cs.meta


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

374
Samples/UIWidgetSample/DragNDrop/CustomInspectorSample.cs


using System.Collections.Generic;
using Unity.UIWidgets.editor;
using Unity.UIWidgets.foundation;
using Unity.UIWidgets.material;
using Unity.UIWidgets.painting;
using Unity.UIWidgets.rendering;
using Unity.UIWidgets.service;
using Unity.UIWidgets.ui;
using Unity.UIWidgets.widgets;
using UnityEditor;
using UnityEngine;
using Color = Unity.UIWidgets.ui.Color;
using Transform = UnityEngine.Transform;
namespace UIWidgetsSample.DragNDrop {
public class CustomInspectorSample : UIWidgetsEditorWindow {
[MenuItem("UIWidgetsTests/Drag&Drop/Custom Inspector")]
public static void ShowEditorWindow() {
var window = GetWindow<CustomInspectorSample>();
window.titleContent.text = "Custom Inspector Sample";
}
protected override void OnEnable() {
FontManager.instance.addFont(Resources.Load<Font>("MaterialIcons-Regular"), "Material Icons");
FontManager.instance.addFont(Resources.Load<Font>("GalleryIcons"), "GalleryIcons");
base.OnEnable();
}
protected override Widget createWidget() {
Debug.Log("[ WIDGET RECREATED ]");
return new MaterialApp(
home: new CustomInspectorSampleWidget(),
darkTheme: new ThemeData(primaryColor: Colors.black26)
);
}
}
public class CustomInspectorSampleWidget : StatefulWidget {
public CustomInspectorSampleWidget(Key key = null) : base(key) {
}
public override State createState() {
return new CustomInspectorSampleWidgetState();
}
}
public class CustomInspectorSampleWidgetState : State<CustomInspectorSampleWidget> {
GameObject objectRef;
Transform transformRef;
TextEditingController textController = new TextEditingController();
public override void initState() {
this.textController.addListener(() => {
var text = this.textController.text.ToLower();
this.textController.value = this.textController.value.copyWith(
text: text,
selection: new TextSelection(baseOffset: text.Length, extentOffset: text.Length),
composing: TextRange.empty
);
});
base.initState();
}
enum ETransfrom {
Position,
Rotation,
Scale
}
// make custom control of cursor position in TextField.
int oldCursorPosition = 0;
// The decimal point input-and-parse exists problem.
Widget getCardRow(ETransfrom type, bool hasRef) {
var xValue = hasRef
? type == ETransfrom.Position
? this.transformRef.position.x.ToString()
: type == ETransfrom.Rotation
? this.transformRef.localEulerAngles.x.ToString()
: this.transformRef.localScale.x.ToString()
: "";
// Using individual TextEditingController to control TextField cursor position.
var xValueController = TextEditingController.fromValue(
new TextEditingValue(xValue, TextSelection.collapsed(this.oldCursorPosition))
);
var yValue = hasRef
? type == ETransfrom.Position
? this.transformRef.position.y.ToString()
: type == ETransfrom.Rotation
? this.transformRef.localEulerAngles.y.ToString()
: this.transformRef.localScale.y.ToString()
: "";
var yValueController = TextEditingController.fromValue(
new TextEditingValue(yValue, TextSelection.collapsed(this.oldCursorPosition))
);
var zValue = hasRef
? type == ETransfrom.Position
? this.transformRef.position.z.ToString()
: type == ETransfrom.Rotation
? this.transformRef.localEulerAngles.z.ToString()
: this.transformRef.localScale.z.ToString()
: "";
var zValueController = TextEditingController.fromValue(
new TextEditingValue(zValue, TextSelection.collapsed(this.oldCursorPosition))
);
return new Column(
children: new List<Widget> {
new Container(
padding: EdgeInsets.symmetric(vertical: 8f),
child: new Align(
alignment: Alignment.centerLeft,
child: new Text(
type == ETransfrom.Position ? "Position" :
type == ETransfrom.Rotation ? "Rotation" : "Scale",
style: new TextStyle(fontSize: 16.0f)
)
)
),
new Row(
children: new List<Widget> {
new Flexible(
flex: 8,
child: new Container(
decoration: new BoxDecoration(
color: new Color(0xfff5f5f5)),
child: new TextField(
decoration: new InputDecoration(
border: new UnderlineInputBorder(),
contentPadding:
EdgeInsets.symmetric(
horizontal: 10f, vertical: 5f),
labelText: "X"
),
controller: xValueController,
onChanged: hasRef
? (str) => {
// While the TextField value changed, try to parse and assign to transformRef.
this.setState(() => {
float result = 0;
float.TryParse(str, out result);
if (str == "" || str[0] == '0') {
this.oldCursorPosition = 1;
}
else {
this.oldCursorPosition =
xValueController.selection.startPos.offset;
}
switch (type) {
case ETransfrom.Position:
var newPos = this.transformRef.position;
newPos.x = result;
this.transformRef.position = newPos;
break;
case ETransfrom.Rotation:
var newRot = this.transformRef.localEulerAngles;
newRot.x = result;
this.transformRef.localEulerAngles = newRot;
break;
case ETransfrom.Scale:
var newScale = this.transformRef.localScale;
newScale.x = result;
this.transformRef.localScale = newScale;
break;
}
});
}
: (ValueChanged<string>) null
)
)),
new Flexible(
child: new Container()
),
new Flexible(
flex: 8,
child: new Container(
decoration: new BoxDecoration(
color: new Color(0xfff5f5f5)),
child: new TextField(
decoration: new InputDecoration(
border: new UnderlineInputBorder(),
contentPadding:
EdgeInsets.symmetric(
horizontal: 10f, vertical: 5f),
labelText: "Y"
),
controller: yValueController,
onChanged: hasRef
? (str) => {
this.setState(() => {
float result = 0;
float.TryParse(str, out result);
if (str == "" || str[0] == '0') {
this.oldCursorPosition = 1;
}
else {
this.oldCursorPosition =
yValueController.selection.startPos.offset;
}
switch (type) {
case ETransfrom.Position:
var newPos = this.transformRef.position;
newPos.y = result;
this.transformRef.position = newPos;
break;
case ETransfrom.Rotation:
var newRot = this.transformRef.localEulerAngles;
newRot.y = result;
this.transformRef.localEulerAngles = newRot;
break;
case ETransfrom.Scale:
var newScale = this.transformRef.localScale;
newScale.y = result;
this.transformRef.localScale = newScale;
break;
}
});
}
: (ValueChanged<string>) null
)
)),
new Flexible(
child: new Container()
),
new Flexible(
flex: 8,
child: new Container(
decoration: new BoxDecoration(
color: new Color(0xfff5f5f5)),
child: new TextField(
decoration: new InputDecoration(
border: new UnderlineInputBorder(),
contentPadding:
EdgeInsets.symmetric(
horizontal: 10f, vertical: 5f),
labelText: "Z"
),
controller: zValueController,
onChanged: hasRef
? (str) => {
this.setState(() => {
float result = 0;
float.TryParse(str, out result);
if (str == "" || str[0] == '0') {
this.oldCursorPosition = 1;
}
else {
this.oldCursorPosition =
zValueController.selection.startPos.offset;
}
switch (type) {
case ETransfrom.Position:
var newPos = this.transformRef.position;
newPos.z = result;
this.transformRef.position = newPos;
break;
case ETransfrom.Rotation:
var newRot = this.transformRef.localEulerAngles;
newRot.z = result;
this.transformRef.localEulerAngles = newRot;
break;
case ETransfrom.Scale:
var newScale = this.transformRef.localScale;
newScale.z = result;
this.transformRef.localScale = newScale;
break;
}
});
}
: (ValueChanged<string>) null
)
))
}
)
}
);
}
public override Widget build(BuildContext context) {
return new Theme(
data: new ThemeData(
appBarTheme: new AppBarTheme(
color: Colors.purple
),
cardTheme: new CardTheme(
color: Colors.white,
elevation: 2.0f
)
),
child: new Scaffold(
appBar: new AppBar(title: new Text("Custom Inspector")),
body: new ListView(
children: new List<Widget> {
new Card(
clipBehavior: Clip.antiAlias,
margin: EdgeInsets.all(20.0f),
shape: new RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0f)
),
child: new Container(
padding: EdgeInsets.symmetric(vertical: 20f, horizontal: 10f),
child: new Column(
mainAxisSize: MainAxisSize.min,
children: new List<Widget> {
new UnityObjectDetector(
// When receiving a GameObject, get its transfrom.
onRelease: (details) => {
this.setState(() => {
var gameObj = details.objectReferences[0] as GameObject;
if (gameObj) {
this.objectRef = gameObj;
if (this.objectRef) {
this.transformRef = this.objectRef.transform;
}
}
});
},
child: new ListTile(
title: new Text(
this.objectRef == null ? "Object Name" : this.objectRef.name,
style: new TextStyle(fontSize: 28.0f)),
subtitle: new Text("Drag an object here",
style: new TextStyle(fontSize: 16.0f)),
contentPadding: EdgeInsets.symmetric(horizontal: 10f)
)
),
new Card(
clipBehavior: Clip.antiAlias,
shape: new RoundedRectangleBorder(
borderRadius: BorderRadius.circular(20.0f)
),
child: new Container(
padding: EdgeInsets.symmetric(horizontal: 10.0f),
child: new Column(
mainAxisSize: MainAxisSize.min,
children: new List<Widget> {
new Container(
padding: EdgeInsets.only(top: 20f),
child: new Align(
alignment: Alignment.centerLeft,
child: new Text("Transform",
style: new TextStyle(fontSize: 20.0f))
)
),
this.getCardRow(ETransfrom.Position,
this.objectRef != null),
this.getCardRow(ETransfrom.Rotation,
this.objectRef != null),
this.getCardRow(ETransfrom.Scale, this.objectRef != null),
new Container(padding: EdgeInsets.only(bottom: 20f))
}
)
)
),
}
)
)
)
}
)
)
);
}
}
}
正在加载...
取消
保存