internal void Update() { this.lastSeenEvent = Event.current.type; this.SetCurrentDragAndDropMethod(); if (this.lastSeenEvent == EventType.Repaint) { this.FinalizeDropObject(); } if (Event.current.isMouse || Event.current.type == EventType.DragUpdated) { Rect screenSpaceRect; if (this.DragHandleRect.HasValue) { screenSpaceRect = this.DragHandleRect.Value; } else { screenSpaceRect = this.Rect; } Vector2 screenPos = GUIUtility.GUIToScreenPoint(new Vector2(screenSpaceRect.x, screenSpaceRect.y)); screenSpaceRect.x = screenPos.x; screenSpaceRect.y = screenPos.y; this.IsHovering = screenSpaceRect.Contains(GUIUtility.GUIToScreenPoint(Event.current.mousePosition)); } this.OnDragStarted = false; if (DragAndDropManager.IsDragInProgress == false) { if (Event.current.isMouse) { if (this.IsHovering) { if (this.Enabled && Event.current.type == EventType.MouseDown == true && Event.current.button == 0) { this.isMouseDown = true; this.mouseDownPostionOffset = Event.current.mousePosition - new Vector2(this.Rect.x, this.Rect.y); GUIHelper.RemoveFocusControl(); Event.current.Use(); DragAndDrop.PrepareStartDrag(); } if (this.isMouseDown && Event.current.type == EventType.MouseDrag) { this.isDragging = true; this.OnDragStarted = true; if (this.Object != null) { DragAndDrop.objectReferences = new UnityEngine.Object[0]; DragAndDrop.paths = null; DragAndDrop.SetGenericData(this.Object.GetType().Name, this.Object); DragAndDrop.StartDrag("ODIN Drag Operation"); } } } } } else { GUIHelper.RequestRepaint(); } if (this.isDragging) { GUIHelper.RequestRepaint(); DragAndDropManager.CurrentDraggingHandle = this; if (EditorWindow.mouseOverWindow != null) { EditorWindow.mouseOverWindow.Focus(); } if (DragAndDropManager.WasDragPerformed) { this.IsReadyToBeClaimed = true; if (DragAndDropManager.IsHoveringDropZone == false) { this.DropObject(DropEvents.Canceled); } } } else { if (this.IsHovering) { if (currentHoveringDragHandle == null || this.LayoutDepth >= currentHoveringDragHandle.LayoutDepth) { currentHoveringDragHandle = this; } } else if (currentHoveringDragHandle == this) { currentHoveringDragHandle = null; } this.IsHovering = currentHoveringDragHandle == this; } }
/// <summary> /// Begins the table. /// </summary> public void BeginTable(int rowCount) { marginFix = marginFix ?? new GUIStyle(); this.currColIndex = 0; this.rows = this.rows ?? new TableRow[0]; if (this.rowCount != rowCount) { this.isDirty = 3; this.rowCount = rowCount; } this.RowIndexFrom = Math.Min(this.rowCount, this.RowIndexFrom); this.RowIndexTo = Math.Min(this.rowCount, this.RowIndexTo); if (this.rows.Length != rowCount) { Array.Resize(ref this.rows, rowCount); } if (Event.current.type == EventType.Layout) { for (int i = this.RowIndexFrom; i < this.RowIndexTo; i++) { var row = rows[i]; if (row.tmpRowHeight > 0) { if (row.rowHeight != row.tmpRowHeight) { this.isDirty = 3; row.rowHeight = row.tmpRowHeight; } row.tmpRowHeight = 0; this.rows[i] = row; } } if (this.isDirty > 0) { this.UpdateSpaceAllocation(); GUIHelper.RequestRepaint(); } } if (Event.current.type == EventType.Repaint) { var p = GUIUtility.GUIToScreenPoint(this.OuterRect.position); if (this.outerVisibleRect != p) { this.outerVisibleRect = p; this.isDirty = 3; } } var outerRect = EditorGUILayout.BeginVertical(this.GetOuterRectLayoutOptions()); if (Event.current.type != EventType.Layout && outerRect.height > 1 || Event.current.type == EventType.Repaint) { if (this.OuterRect != outerRect) { this.isDirty = 3; this.OuterRect = outerRect; } } Vector2 newScrollPos; if (this.DrawScrollBars()) { newScrollPos = GUILayout.BeginScrollView(this.ScrollPos, false, false, this.GetScrollViewOptions(true)); } else { this.ignoreScrollView = Event.current.rawType == EventType.ScrollWheel; if (this.ignoreScrollView) GUIHelper.PushEventType(EventType.Ignore); newScrollPos = GUILayout.BeginScrollView(this.ScrollPos, false, false, GUIStyle.none, GUIStyle.none, this.GetScrollViewOptions(false)); if (this.ignoreScrollView) { GUIHelper.PopEventType(); this.isDirty = 3; } } if (newScrollPos != this.ScrollPos) { this.nextScrollPos = newScrollPos; this.isDirty = 3; } var rect = GUILayoutUtility.GetRect(0, this.totalHeight); if (Event.current.type != EventType.Layout && rect.width > 1) { this.innerVisibleRect = GUIClipInfo.VisibleRect; if (this.DrawScrollView) { var scrollDelta = this.nextScrollPos - this.ScrollPos; this.innerVisibleRect.y += scrollDelta.y; if (scrollDelta != Vector2.zero) { this.isDirty = 3; } } if (rect != this.contentRect) { this.isDirty = 3; } if (this.contentRect != rect) { this.isDirty = 3; } this.contentRect = rect; } if (this.isDirty > 0) { GUIHelper.RequestRepaint(); if (Event.current.type == EventType.Repaint) { this.isDirty--; } } }
/// <summary> /// A draggable zone for both Unity and non-unity objects. /// </summary> public static object DragZone(Rect rect, object value, Type type, bool allowMove, bool allowSwap, int id) { var tmpNextPreventedDropArea = nextPreventDropAreaRect; nextPreventDropAreaRect = new Rect(); if (value == null) { return(null); } // Unity null if (!(value as UnityEngine.Object) && typeof(UnityEngine.Object).IsAssignableFrom(value.GetType())) { return(value); } var t = Event.current.type; var isMouseOver = rect.Contains(Event.current.mousePosition); var unityObject = value as UnityEngine.Object; if (isMouseOver && t == EventType.MouseDown) { GUIHelper.RemoveFocusControl(); GUIUtility.hotControl = id; GUIUtility.keyboardControl = id; dragginObjects = new object[] { }; DragAndDrop.PrepareStartDrag(); GUIHelper.RequestRepaint(); isAccepted = false; dropZoneObject = null; draggingId = 0; preventDropAreaRect = new Rect(); currentDragIsMove = false; Event.current.Use(); } if (isAccepted && draggingId == id) { GUIHelper.RequestRepaint(); GUI.changed = true; draggingId = 0; preventDropAreaRect = new Rect(); // TODO: Validate drop zone object, and only return that if it's assignable from type. return(allowMove ? (allowSwap ? dropZoneObject : null) : value); } if (GUIUtility.hotControl != id) { return(value); } else if (t == EventType.MouseMove) { GUIHelper.RequestRepaint(); draggingId = 0; preventDropAreaRect = new Rect(); DragAndDrop.PrepareStartDrag(); DragAndDrop.objectReferences = new UnityEngine.Object[] { }; GUIHelper.RemoveFocusControl(); dragginObjects = new object[] { }; currentDragIsMove = false; } if (Event.current.type == EventType.MouseDrag && isMouseOver && (DragAndDrop.objectReferences == null || DragAndDrop.objectReferences.Length == 0)) { isAccepted = false; dropZoneObject = null; draggingId = id; OnDragStartMouseScreenPos = GUIUtility.GUIToScreenPoint(Event.current.mousePosition); DragAndDrop.StartDrag("Movable drag"); preventDropAreaRect = tmpNextPreventedDropArea.Expand(1); if (unityObject) { DragAndDrop.objectReferences = new UnityEngine.Object[] { unityObject }; dragginObjects = new object[] { }; } else { DragAndDrop.objectReferences = new UnityEngine.Object[] { }; dragginObjects = new object[] { value }; } DragAndDrop.activeControlID = 0; currentDragIsMove = allowMove; Event.current.Use(); GUIHelper.RequestRepaint(); } return(value); }
/// <summary> /// A drop zone area for bot Unity and non-unity objects. /// </summary> public static object DropZone(Rect rect, object value, Type type, bool allowSceneObjects, int id) { if (rect.Contains(Event.current.mousePosition)) { var t = Event.current.type; if (t == EventType.DragUpdated || t == EventType.DragPerform) { // This bit disables all dropzones inside the provided preventDropAreaRect. // // RootNode1 // ChileNode1 // ChileNode2 // ChileNode2.1 // ChileNode2.2 // ChileNode3 // RootNode2 // // If the RootNode has provided a preventDropAreaRect, then that means that the RootNode won't be able to be dragged into any of its child nodes. if (preventDropAreaRect.Contains(new Vector2(rect.x, rect.y)) && preventDropAreaRect.Contains(new Vector2(rect.xMax, rect.yMax))) { return(value); } object obj = null; if (obj == null) { obj = dragginObjects.Where(x => x != null && x.GetType().InheritsFrom(type)).FirstOrDefault(); } if (obj == null) { obj = DragAndDrop.objectReferences.Where(x => x != null && x.GetType().InheritsFrom(type)).FirstOrDefault(); } if (type.InheritsFrom <Component>() || type.IsInterface) { if (obj == null) { obj = dragginObjects.OfType <GameObject>().Where(x => x != null).Select(x => x.GetComponent(type)).Where(x => x != null).FirstOrDefault(); } if (obj == null) { obj = DragAndDrop.objectReferences.OfType <GameObject>().Where(x => x != null).Select(x => x.GetComponent(type)).Where(x => x != null).FirstOrDefault(); } } bool acceptsDrag = obj != null; if (acceptsDrag && allowSceneObjects == false) { var uObj = obj as UnityEngine.Object; if (uObj != null) { if (typeof(Component).IsAssignableFrom(uObj.GetType())) { uObj = ((Component)uObj).gameObject; } acceptsDrag = EditorUtility.IsPersistent(uObj); } } if (acceptsDrag) { hoveringAcceptedDropZone = id; bool move = Event.current.modifiers != EventModifiers.Control && draggingId != 0 && currentDragIsMove; if (move) { DragAndDrop.visualMode = DragAndDropVisualMode.Move; } else { DragAndDrop.visualMode = DragAndDropVisualMode.Copy; } Event.current.Use(); if (t == EventType.DragPerform) { if (!move) { draggingId = 0; //preventDropAreaRect = new Rect(); } // Calling this here makes Unity crash on MacOS // DragAndDrop.objectReferences = new UnityEngine.Object[] { }; DragAndDrop.AcceptDrag(); GUI.changed = true; GUIHelper.RemoveFocusControl(); dragginObjects = new object[] { }; currentDragIsMove = false; isAccepted = true; dropZoneObject = value; preventDropAreaRect = new Rect(); DragAndDrop.activeControlID = 0; GUIHelper.RequestRepaint(); return(obj); } else { DragAndDrop.activeControlID = id; } } else { hoveringAcceptedDropZone = 0; DragAndDrop.visualMode = DragAndDropVisualMode.Rejected; } } } else { if (hoveringAcceptedDropZone == id) { hoveringAcceptedDropZone = 0; } } return(value); }
/// <summary> /// Draws a objectpicker button in the given rect. This one is designed to look good on top of DrawDropZone(). /// </summary> public static object ObjectPickerZone(Rect rect, object value, Type type, bool allowSceneObjects, int id) { var btnId = GUIUtility.GetControlID(FocusType.Passive); var objectPicker = ObjectPicker.GetObjectPicker(type.FullName + "+" + GUIHelper.CurrentWindowInstanceID.ToString() + "+" + id, type); var selectRect = rect.AlignBottom(15).AlignCenter(45); var uObj = value as UnityEngine.Object; selectRect.xMin = Mathf.Max(selectRect.xMin, rect.xMin); var hide = IsDragging || Event.current.type == EventType.Repaint && !rect.Contains(Event.current.mousePosition); if (hide) { GUIHelper.PushColor(new Color(0, 0, 0, 0)); GUIHelper.PushGUIEnabled(false); } bool hideInspectorBtn = !hide && !(uObj); if (hideInspectorBtn) { GUIHelper.PushGUIEnabled(false); GUIHelper.PushColor(new Color(0, 0, 0, 0)); } var inspectBtn = rect.AlignRight(14); inspectBtn.height = 14; SirenixEditorGUI.BeginDrawOpenInspector(inspectBtn, uObj, rect); SirenixEditorGUI.EndDrawOpenInspector(inspectBtn, uObj); if (hideInspectorBtn) { GUIHelper.PopColor(); GUIHelper.PopGUIEnabled(); } if (GUI.Button(selectRect, "select", SirenixGUIStyles.TagButton)) { GUIHelper.RemoveFocusControl(); objectPicker.ShowObjectPicker(value, allowSceneObjects, rect, false); Event.current.Use(); } if (Event.current.keyCode == KeyCode.Return && Event.current.type == EventType.KeyDown && EditorGUIUtility.keyboardControl == id) { objectPicker.ShowObjectPicker(value, allowSceneObjects, rect, false); Event.current.Use(); } if (hide) { GUIHelper.PopColor(); GUIHelper.PopGUIEnabled(); } if (objectPicker.IsReadyToClaim) { GUIHelper.RequestRepaint(); GUI.changed = true; var newValue = objectPicker.ClaimObject(); Event.current.Use(); return(newValue); } if (objectPicker.IsPickerOpen && typeof(UnityEngine.Object).IsAssignableFrom(type)) { return(objectPicker.CurrentSelectedObject); } if (Event.current.keyCode == KeyCode.Delete && Event.current.type == EventType.KeyDown && EditorGUIUtility.keyboardControl == id) { Event.current.Use(); GUI.changed = true; return(null); } if (uObj && Event.current.rawType == EventType.MouseUp && rect.Contains(Event.current.mousePosition) && Event.current.button == 0) { // For components ping the attached game object instead, because then Unity can figure out to ping prefabs in the project window too. UnityEngine.Object pingObj = uObj; if (pingObj is Component) { pingObj = (pingObj as Component).gameObject; } EditorGUIUtility.PingObject(pingObj); } return(value); }
/// <summary> /// Recaluclates cell and column sizes in the next frame. /// </summary> public void MarkDirty() { this.isDirty = true; GUIHelper.RequestRepaint(); }
/// <summary> /// Draws the table. /// </summary> public void DrawTable() { var e = Event.current.type; if (this.minTalbeSize.y == 0 || this.isDirty) { this.ReCalculateSizes(); } // If there are not auto-width columns it means that the table has a fixed width, and doesn't expand. // Otherwise it does expand. // Here we also make sure that we allocate atleast 10 pixels per auto-width column. GUILayoutOptions.GUILayoutOptionsInstance guiLayoutOptions; if (this.numOfAutoWidthColumns == 0) { guiLayoutOptions = GUILayoutOptions.ExpandWidth(false).Width(this.minTalbeSize.x); } else { guiLayoutOptions = GUILayoutOptions.ExpandWidth().MinWidth(this.minTalbeSize.x + this.numOfAutoWidthColumns * 10); } var newRect = GUILayoutUtility.GetRect(0, this.minTalbeSize.y > 0 ? this.minTalbeSize.y : 10, guiLayoutOptions); if (this.RespectIndentLevel) { newRect = UnityEditor.EditorGUI.IndentedRect(newRect); } // Recalcualte sizes if resized. if (e == EventType.Repaint) { if (this.tableRect.width != newRect.width || this.tableRect.x != newRect.x || this.tableRect.y != newRect.y) { this.tableRect = newRect; this.ReCalculateSizes(); } else { this.tableRect = newRect; } } // Handle resizing: for (int x = 0; x < this.ColumnCount - 1; x++) { if (x < this.ColumnCount - 1 && this.columnInfos[x + 1].Resizable == false) { continue; } if (this.columnInfos[x].Resizable == false) { continue; } GUITableCell resizeCell = null; for (int y = 0; y < this.RowCount; y++) { var candidate = this.cells[x, y]; if (candidate != null && candidate.SpanX == false) { resizeCell = candidate; break; } } if (resizeCell != null) { var rect = resizeCell.Rect; rect.x = rect.xMax - 5; rect.width = 10; var mouseDelta = SirenixEditorGUI.SlideRect(rect).x; if (mouseDelta != 0) { if (mouseDelta > 0) { var ci = this.columnInfos[x]; ColumnInfo nextResizableCol = null; for (int j = x + 1; j < this.ColumnCount; j++) { if (this.columnInfos[j].Resizable) { nextResizableCol = this.columnInfos[j]; break; } } if (nextResizableCol != null) { float remaining = nextResizableCol.ColumnWidth - nextResizableCol.ColumnMinWidth; if (nextResizableCol != null && remaining > 0) { mouseDelta = Mathf.Min(mouseDelta, remaining); ci.ResizeOffset += mouseDelta; nextResizableCol.ResizeOffset -= mouseDelta; } this.ReCalculateSizes(); } } else { var ci = this.columnInfos[x + 1]; mouseDelta *= -1; ColumnInfo prevResizableCol = null; for (int j = x; j >= 0; j--) { if (this.columnInfos[j].Resizable) { prevResizableCol = this.columnInfos[j]; break; } } if (prevResizableCol != null) { float remaining = prevResizableCol.ColumnWidth - prevResizableCol.ColumnMinWidth; if (prevResizableCol != null && remaining > mouseDelta) { mouseDelta = Mathf.Min(mouseDelta, remaining); ci.ResizeOffset += mouseDelta; prevResizableCol.ResizeOffset -= mouseDelta; } } this.ReCalculateSizes(); } } } } GUIHelper.PushIndentLevel(0); // Draw Cells: for (int x = 0; x < this.ColumnCount; x++) { for (int y = 0; y < this.RowCount; y++) { var cell = this.cells[x, y]; if (cell != null) { cell.Draw(); } } } GUIHelper.PopIndentLevel(); }