/// <summary> /// Determines whether current event is a mouse drag event. /// /// True if has DragAndDropObjectReferences. /// /// True if mouse has moved since mouse button was pressed down and last input event type is MouseDrag, DragUpdated, or MouseDown for left mouse button. /// /// True if mouse has moved since mouse button was pressed down and current input event type is DragPerform, DragExited. /// /// NOTE: This can return true for the remaining duration of the the frame, even after MouseDownInfo.Clear(true) has been called. /// /// NOTE: This can return true, even if mouse down event was used. /// </summary> /// <returns> True if event is a mouse drag event, otherwise returns false. </returns> public bool IsDrag() { //UPDATE: The DragAndDropObjectReferences check is important //as without it the check would fail at random times when dragging //a MonoScript from the Project view on the custom InspectorWindow if (DrawGUI.IsUnityObjectDrag) { return(true); } if (isClick) { return(false); } switch (DrawGUI.LastInputEventType) { case EventType.DragPerform: case EventType.DragExited: return(Event.current != null && Event.current.Equals(DrawGUI.LastInputEvent())); case EventType.MouseDrag: case EventType.DragUpdated: return(true); case EventType.MouseDown: var lastInputEvent = DrawGUI.LastInputEvent(); return(lastInputEvent != null && lastInputEvent.button == 0); default: return(false); } }
/// <summary> /// Determines whether current event is a mouse drag event. /// /// True if has DragAndDropObjectReferences. /// /// True if mouse has moved since mouse button was pressed down and last input event type is MouseDrag, DragUpdated, or MouseDown for right mouse button. /// /// True if mouse has moved since mouse button was pressed down and current input event type is DragPerform, DragExited. /// /// NOTE: This can return true for the remaining duration of the the frame, even after Clear has been called. /// /// NOTE: This can return true, even if mouse down event was used. /// </summary> /// <returns> True if event is a mouse drag event, otherwise returns false. </returns> public bool IsDrag() { if (DrawGUI.IsUnityObjectDrag) { return(true); } if (isClick) { return(false); } switch (DrawGUI.LastInputEventType) { case EventType.DragPerform: case EventType.DragExited: return(Event.current != null && Event.current.Equals(DrawGUI.LastInputEvent())); case EventType.MouseDrag: case EventType.DragUpdated: return(true); case EventType.ContextClick: case EventType.MouseDown: var lastInputEvent = DrawGUI.LastInputEvent(); return(lastInputEvent != null && lastInputEvent.button == 1); default: return(false); } }
private static void BeginEditorOrPropertyDrawer(out bool editingTextFieldWas, out EventType eventType, out KeyCode keyCode) { editingTextFieldWas = EditorGUIUtility.editingTextField; eventType = DrawGUI.LastInputEventType; var lastInputEvent = DrawGUI.LastInputEvent(); keyCode = lastInputEvent == null ? KeyCode.None : lastInputEvent.keyCode; }
/// <inheritdoc/> protected override void OnSelectedInternal(ReasonSelectionChanged reason, IDrawer previous, bool isMultiSelection) { #if DEV_MODE && DEBUG_ON_SELECTED Debug.Log(ToString() + ".OnSelectedInternal(" + reason + "," + StringUtils.ToString(previous) + ")"); #endif bool wasUnfolded = false; bool isClick = false; switch (reason) { case ReasonSelectionChanged.PrefixClicked: isClick = true; if (DrawGUI.LastInputEvent().control) { ComponentDrawerUtility.singleInspectedInstance = this; } break; case ReasonSelectionChanged.ControlClicked: if (DrawGUI.LastInputEvent().control) { ComponentDrawerUtility.singleInspectedInstance = this; } return; case ReasonSelectionChanged.ThisClicked: isClick = true; break; } #if UNFOLD_ON_SELECT_IN_SINGLE_ACTIVE_MODE if (UserSettings.EditComponentsOneAtATime && !inspector.HasFilter) { if (ComponentDrawerUtility.singleInspectedInstance != null && ComponentDrawerUtility.singleInspectedInstance != this) { ComponentDrawerUtility.singleInspectedInstance.SetUnfolded(false); } ComponentDrawerUtility.singleInspectedInstance = this; // if Component was clicked, let the click event handle the unfolding if (!Unfolded && (!isClick || (MouseoveredHeaderPart != HeaderPart.FoldoutArrow && !inspector.Preferences.changeFoldedStateOnFirstClick))) { wasUnfolded = true; // allow bypassing EditComponentsOneAtATime functionality by holding down control when clicking the Component header bool collapseAllOthers = !Event.current.control || reason != ReasonSelectionChanged.PrefixClicked; SetUnfolded(true, collapseAllOthers, false); } } #endif base.OnSelectedInternal(reason, previous, isMultiSelection); if (wasUnfolded) { ExitGUIUtility.ExitGUI(); } }
/// <inheritdoc /> protected override void OnSelectedInternal(ReasonSelectionChanged reason, IDrawer previous, bool isMultiSelection) { bool isClick = false; switch (reason) { case ReasonSelectionChanged.PrefixClicked: isClick = true; if (DrawGUI.LastInputEvent().control) { ComponentDrawerUtility.singleInspectedInstance = this; } break; case ReasonSelectionChanged.ControlClicked: if (DrawGUI.LastInputEvent().control) { ComponentDrawerUtility.singleInspectedInstance = this; } return; } #if UNFOLD_ON_SELECT_IN_SINGLE_ACTIVE_MODE if (UserSettings.EditComponentsOneAtATime && !InspectorUtility.ActiveInspector.HasFilter) { if (ComponentDrawerUtility.singleInspectedInstance != null && ComponentDrawerUtility.singleInspectedInstance != this) { ComponentDrawerUtility.singleInspectedInstance.SetUnfolded(false); } ComponentDrawerUtility.singleInspectedInstance = this; // if Component was clicked, let the click event handle the unfolding if (!Unfolded && (!isClick || (MouseoveredHeaderPart != HeaderPart.FoldoutArrow && !inspector.Preferences.changeFoldedStateOnFirstClick))) { SetUnfolded(true, Event.current.alt); } } #endif base.OnSelectedInternal(reason, previous, isMultiSelection); }
/// <inheritdoc/> protected override void OnDeselectedInternal(ReasonSelectionChanged reason, IDrawer losingFocusTo) { #if DEV_MODE && DEBUG_ON_DESELECTED Debug.Log(ToString() + ".OnDeselectedInternal(" + reason + "," + StringUtils.ToString(losingFocusTo) + ")"); #endif bool unfoldIfLostFocus = UserSettings.EditComponentsOneAtATime; switch (reason) { case ReasonSelectionChanged.PrefixClicked: case ReasonSelectionChanged.ControlClicked: if (DrawGUI.LastInputEvent().control) { unfoldIfLostFocus = false; } break; } if (unfoldIfLostFocus) { var test = losingFocusTo; while (test != null) { var component = test as IComponentDrawer; if (component != null) { if (component != this) { SetUnfolded(false, false); } break; } test = test.Parent; } } base.OnDeselectedInternal(reason, losingFocusTo); }
private static void EndEditorOrPropertyDrawer(bool editingTextFieldWas, EventType eventType, KeyCode keyCode) { if (EditorGUIUtility.editingTextField != editingTextFieldWas) { if (eventType != EventType.KeyDown && eventType != EventType.KeyUp) { #if DEV_MODE && DEBUG_SET_EDITING_TEXT_FIELD Debug.Log("DrawGUI.EditingTextField = " + StringUtils.ToColorizedString(EditorGUIUtility.editingTextField) + " with eventType=" + StringUtils.ToString(eventType) + ", keyCode=" + keyCode + ", lastInputEvent=" + StringUtils.ToString(DrawGUI.LastInputEvent())); #endif DrawGUI.EditingTextField = EditorGUIUtility.editingTextField; } else { switch (keyCode) { case KeyCode.UpArrow: case KeyCode.DownArrow: case KeyCode.LeftArrow: case KeyCode.RightArrow: if (!EditorGUIUtility.editingTextField) { #if DEV_MODE Debug.Log("DrawGUI.EditingTextField = " + StringUtils.ToColorizedString(false) + " with eventType=" + StringUtils.ToString(eventType) + ", keyCode=" + keyCode + ", lastInputEvent=" + StringUtils.ToString(DrawGUI.LastInputEvent())); #endif DrawGUI.EditingTextField = false; } else // prevent Unity automatically starting field editing when field focus is changed to a text field, as that is not how Power Inspector functions { #if DEV_MODE Debug.LogWarning("EditorGUIUtility.editingTextField = " + StringUtils.ToColorizedString(false) + " with eventType=" + StringUtils.ToString(eventType) + ", keyCode=" + keyCode + ", lastInputEvent=" + StringUtils.ToString(DrawGUI.LastInputEvent())); #endif EditorGUIUtility.editingTextField = false; } return; default: #if DEV_MODE Debug.Log("DrawGUI.EditingTextField = " + StringUtils.ToColorizedString(false) + " with eventType=" + StringUtils.ToString(eventType) + ", keyCode=" + keyCode + ", lastInputEvent=" + StringUtils.ToString(DrawGUI.LastInputEvent())); #endif DrawGUI.EditingTextField = EditorGUIUtility.editingTextField; return; } } } }
/// <summary> /// This should be called at the beginning of OnGUI of every instance of classes that implement IInspectorDrawer. /// /// SEE ALSO: DrawGUI.BeginOnGUI and InspectorUtility.BeginInspector. /// </summary> /// <param name="inspectorDrawer"> The inspector drawer instance. </param> /// <param name="splittable"> The inspector drawer if it implements ISplittableInspectorDrawer, otherwise null. </param> public static void BeginInspectorDrawer([NotNull] IInspectorDrawer inspectorDrawer, [CanBeNull] ISplittableInspectorDrawer splittable) { #if DEV_MODE && PI_ASSERTATIONS Debug.Assert(inspectorDrawer != null); #endif var manager = inspectorDrawer.Manager; activeInspectorDrawer = inspectorDrawer; ActiveManager = manager; activeManager.ActiveInspector = inspectorDrawer.MainView; var e = Event.current; #if DEV_MODE && PI_ASSERTATIONS Debug.Assert(e != null); #endif var mouseDownInfo = activeManager.MouseDownInfo; // Events like MouseUp, DragUpdated and DragPerformed are normally ignored when the cursor is outside EditorWindow bounds // but when a field is being dragged we still need those events (especially important for the MouseUp event!) var type = mouseDownInfo.GetEventTypeForMouseUpDetection(e); if (mouseDownInfo.NowReordering) { var reordering = mouseDownInfo.Reordering; var dropTarget = reordering.MouseoveredDropTarget; // When reordering and cursor is not above a valid drop target, set DragAndDropVisualMode to rejected, // unless dragging Object references outside window bounds, where want to allow dragging into other // EditorWindows. // UPDATE: This broke drag n drop e.g. from Component header to object reference field inside a custom editor. //if(dropTarget.Parent == null && ((DrawGUI.Active.DragAndDropObjectReferences.Length == 0 || activeManager.MouseoveredInspector != null))) if (dropTarget.Parent == null && DrawGUI.Active.DragAndDropObjectReferences.Length == 0) { #if DEV_MODE Debug.LogWarning("Reordering Rejected because dropTarget.Parent=null && DrawGUI.Active.DragAndDropObjectReferences=" + StringUtils.ToString(DrawGUI.Active.DragAndDropObjectReferences) + ", activeManager.MouseoveredInspector=" + StringUtils.ToString(activeManager.MouseoveredInspector)); #endif // Update: only do this once cursor has moved, otherwise it can look strange during simple click events if (mouseDownInfo.CursorMovedAfterMouseDown) { DrawGUI.Active.DragAndDropVisualMode = DragAndDropVisualMode.Rejected; } } DrawGUI.Active.AddCursorRect(new Rect(0f, 0f, 100000f, 100000f), MouseCursor.MoveArrow); } else if (mouseDownInfo.NowDraggingPrefix) { DrawGUI.Active.SetCursor(MouseCursor.SlideArrow); } switch (type) { case EventType.Repaint: if (inspectorDrawer.MainView.RequiresConstantRepaint() || (splittable != null && splittable.ViewIsSplit && splittable.SplitView.RequiresConstantRepaint())) { inspectorDrawer.Repaint(); } break; case EventType.Layout: activeManager.OnLayout(); UpdateDimensions(inspectorDrawer, splittable); break; case EventType.ValidateCommand: inspectorDrawer.OnValidateCommand(e); break; case EventType.ExecuteCommand: if (OnExecuteCommand != null) { if (inspectorDrawer == manager.FirstInspectorDrawer) { #if DEV_MODE && DEBUG_EXECUTE_COMMAND Debug.Log("ExecuteCommand(" + e.commandName + ")"); #endif OnExecuteCommand(ActiveManager.LastSelectedActiveOrDefaultInspector(), e.commandName); } #if DEV_MODE && DEBUG_EXECUTE_COMMAND else { Debug.Log("ExecuteCommand(" + e.commandName + ") not sent with e=" + StringUtils.ToString(e) + ", OnExecuteCommand=" + StringUtils.ToString(OnExecuteCommand)); } #endif } inspectorDrawer.OnExecuteCommand(e); break; case EventType.MouseUp: case EventType.DragPerform: #if DEV_MODE && (DEBUG_MOUSE_UP || DEBUG_DRAG_N_DROP) Debug.Log(type + " with IsUnityObjectDrag=" + StringUtils.True + ", MouseDownInfo.Inspector=" + activeManager.MouseDownInfo.Inspector + ", activeInspectorDrawer.MouseIsOver=" + (inspectorDrawer == null ? StringUtils.Null : StringUtils.ToColorizedString(inspectorDrawer.MouseIsOver))); #endif inspectorDrawer.Repaint(); mouseDownInfo.OnMouseUp(activeManager); break; case EventType.DragExited: //IMPORTANT NOTE: DragExited gets called when during DragNDrop cursor leaves EditorWindow bounds! #if DEV_MODE && UNITY_EDITOR Debug.Log(type + " with LastInputEvent().type=" + DrawGUI.LastInputEvent().type + ", IsUnityObjectDrag=" + StringUtils.ToColorizedString(DrawGUI.IsUnityObjectDrag) + ", EditorWindow.focusedWindow=" + UnityEditor.EditorWindow.focusedWindow + ", activeManager.MouseoveredInspector=" + activeManager.MouseoveredInspector + ", mouseoveredDrawer.position=" + (activeManager.MouseoveredInspector == null || activeManager.MouseoveredInspector.InspectorDrawer == null ? StringUtils.Null : activeManager.MouseoveredInspector.InspectorDrawer.position.ToString()) + ", MouseDownInfo.Inspector=" + activeManager.MouseDownInfo.Inspector + ", Drawer.MouseIsOver=" + (activeInspectorDrawer == null ? StringUtils.Null : StringUtils.ToColorizedString(activeInspectorDrawer.MouseIsOver))); #endif if (mouseDownInfo.IsDragExitedReallyMouseLeaveWindowEvent()) { #if DEV_MODE Debug.LogWarning("Ignoring DragExited call because IsDragExitedReallyMouseLeaveWindowEvent=" + StringUtils.True + " - cursor probably just left EditorWindow bounds."); #endif break; } inspectorDrawer.Repaint(); mouseDownInfo.OnMouseUp(activeManager); break; case EventType.MouseDown: ActiveManager.MouseDownInfo.OnMouseDown(); #if DEV_MODE && DEBUG_ON_MOUSE_DOWN Debug.Log("MouseDown with button=" + e.button + ", keyCode=" + e.keyCode + ", MouseoveredSelectable=" + StringUtils.ToString(ActiveManager.MouseoveredSelectable)); #endif break; case EventType.KeyDown: inspectorDrawer.OnKeyDown(e); break; case EventType.KeyUp: inspectorDrawer.Manager.OnKeyUp(e); break; } }
/// <summary> /// This is called every frame after cursor has left the bounds of the Inspector window during a drag-n-drop event. /// Each frame we try and firure out whether or not a drag n drop is still happening, and once we know it, /// adjust MouseDownInfo state accordingly. /// </summary> /// <param name="newPosition"> The new position. </param> private void HandleDragAfterCursorEnteredInspector(Vector2 newPosition) { var e = Event.current; if (e == null) { #if DEV_MODE Debug.LogWarning("HandleDragAfterCursorEnteredInspector - ignoring because not mouse event: " + StringUtils.ToString(e)); #endif return; } switch (e.type) { case EventType.DragUpdated: case EventType.MouseDrag: // it's a drag! #if DEV_MODE Debug.LogWarning("HandleDragAfterCursorEnteredInspector - restoring Drag because event=" + StringUtils.ToString(e)); #endif #if DEV_MODE Debug.LogError("STOPPED LISTENING - IS DRAG!!!"); #endif Cursor.OnPositionChanged -= HandleDragAfterCursorEnteredInspector; mouseoveredInspectorLeftDuringDrag = false; MouseButtonIsDown = true; IsClick = false; var draggedObjects = DrawGUI.Active.DragAndDropObjectReferences; if (draggedObjects != null) { MouseButtonIsDown = true; IsClick = false; OnDragStarted(inspector, draggedObjects); } break; //case EventType.Layout: //I think that DragUpdated should always get called instead of Layout during Drags. UPDATE: Noup. At least gets called during frame that cursor enters a new inspector during a drag. case EventType.MouseMove: case EventType.MouseDown: case EventType.MouseUp: #if DEV_MODE Debug.LogError("STOPPED LISTENING - NOT DRAG!!!"); #endif // it's no longer a drag... Cursor.OnPositionChanged -= HandleDragAfterCursorEnteredInspector; #if DEV_MODE Debug.LogWarning("HandleDragAfterCursorEnteredInspector - discarding Drag because event=" + StringUtils.ToString(e)); #endif var lastInputEvent = DrawGUI.LastInputEvent(); if (lastInputEvent != null) { var type = lastInputEvent.type; if (type != EventType.DragExited && type != EventType.MouseUp) { var setLastInputEvent = new Event(lastInputEvent); setLastInputEvent.type = mouseoveredInspectorLeftDuringDrag || DrawGUI.IsUnityObjectDrag ? EventType.DragExited : EventType.MouseUp; DrawGUI.Use(setLastInputEvent); } } Clear(true); mouseoveredInspectorLeftDuringDrag = false; #if DEV_MODE && PI_ASSERTATIONS Debug.Assert(!IsClick, "IsClick was true after MouseDownInfo.Clear was called during event " + StringUtils.ToString(e)); Debug.Assert(!MouseButtonIsDown, "MouseButtonIsDown was true after MouseDownInfo.Clear was called during event " + StringUtils.ToString(e)); Debug.Assert(!IsDrag(), "IsDrag was true after MouseDownInfo.Clear was called during event " + StringUtils.ToString(e)); #endif break; } }
/// <summary> /// If DrawGUI.EditingTextField and EditorGUIUtility.editingTextField values are not in sync, /// then figures out which should take precedence over the other, and syncs their values accordingly. /// </summary> public static void SyncEditingTextField() { if (DrawGUI.EditingTextField == EditorGUIUtility.editingTextField) { return; } var manager = InspectorUtility.ActiveManager; if (manager == null) { DrawGUI.EditingTextField = EditorGUIUtility.editingTextField; return; } var lastInputEvent = DrawGUI.LastInputEvent(); if (lastInputEvent == null) { DrawGUI.EditingTextField = EditorGUIUtility.editingTextField; return; } if (lastInputEvent.isMouse) { // something else than Power Inspector was probably clicked if (manager.MouseoveredInspector == null) { #if DEV_MODE && DEBUG_SYNC_EDITING_TEXT_FIELD Debug.Log("DrawGUI.editingTextField = " + StringUtils.ToColorizedString(EditorGUIUtility.editingTextField) + " with lastInputEvent=" + StringUtils.ToString(lastInputEvent) + " because MouseoveredInspector=" + StringUtils.Null); #endif DrawGUI.EditingTextField = EditorGUIUtility.editingTextField; } // editing text fields is not allowed when multiple controls are selected else if (manager.HasMultiSelectedControls) { #if DEV_MODE && DEBUG_SYNC_EDITING_TEXT_FIELD Debug.Log("DrawGUI.EditingTextField = " + StringUtils.False + " with lastInputEvent=" + StringUtils.ToString(lastInputEvent) + " because HasMultiSelectedControls=" + StringUtils.True); #endif DrawGUI.EditingTextField = false; } else { #if DEV_MODE && DEBUG_SYNC_EDITING_TEXT_FIELD Debug.LogWarning("EditorGUIUtility.editingTextField = " + StringUtils.ToColorizedString(DrawGUI.EditingTextField) + " with lastInputEvent=" + StringUtils.ToString(lastInputEvent)); #endif EditorGUIUtility.editingTextField = DrawGUI.EditingTextField; } } else if (manager.SelectedInspector == null || !manager.SelectedInspector.InspectorDrawer.HasFocus) { #if DEV_MODE && DEBUG_SYNC_EDITING_TEXT_FIELD Debug.Log("DrawGUI.editingTextField = " + StringUtils.ToColorizedString(EditorGUIUtility.editingTextField) + " with lastInputEvent=" + StringUtils.ToString(lastInputEvent) + " because MouseoveredInspector=" + StringUtils.Null); #endif DrawGUI.EditingTextField = EditorGUIUtility.editingTextField; } else { #if DEV_MODE && DEBUG_SYNC_EDITING_TEXT_FIELD Debug.LogWarning("EditorGUIUtility.editingTextField = " + StringUtils.ToColorizedString(DrawGUI.EditingTextField) + " with lastInputEvent=" + StringUtils.ToString(lastInputEvent)); #endif EditorGUIUtility.editingTextField = DrawGUI.EditingTextField; } }