/// <summary> /// Triggered when the user releases a mouse button. /// </summary> /// <param name="ev">Information about the mouse release event.</param> private void OnPointerReleased(PointerEvent ev) { if (isDragInProgress) { Cursor.Show(); Cursor.ClipDisable(); } isButtonHeld = false; isDragInProgress = false; guiCurveEditor.OnPointerReleased(ev); }
/// <summary> /// Triggers when some pointing device (mouse cursor, touch) button is released. /// </summary> /// <param name="screenPos">Screen position where the input event occurred.</param> /// <param name="delta">Change in movement since last sent event.</param> /// <param name="button">Button that triggered the pointer event. Might be irrelevant depending on event type. /// (for example move events don't correspond to a button.</param> /// <param name="shift">Is shift button on the keyboard being held down.</param> /// <param name="ctrl">Is control button on the keyboard being held down.</param> /// <param name="alt">Is alt button on the keyboard being held down.</param> /// <param name="scrollAmount">If mouse wheel is being scrolled, what is the amount. Only relevant for /// move events.</param> private static void Internal_TriggerPointerReleased(Vector2I screenPos, Vector2I delta, PointerButton button, bool shift, bool ctrl, bool alt, float scrollAmount) { PointerEvent ev = new PointerEvent(screenPos, delta, button, shift, ctrl, alt, scrollAmount); if (OnPointerReleased != null) OnPointerReleased(ev); }
/// <summary> /// Triggered when the user moves the mouse. /// </summary> /// <param name="ev">Information about the mouse move event.</param> private void OnPointerMoved(PointerEvent ev) { guiCurveEditor.OnPointerMoved(ev); if (isButtonHeld) { Vector2I windowPos = ScreenToWindowPos(ev.ScreenPos); int distance = Vector2I.Distance(dragStartPos, windowPos); if (distance >= DRAG_START_DISTANCE) { isDragInProgress = true; Cursor.Hide(); Rect2I clipRect; clipRect.x = ev.ScreenPos.x - 2; clipRect.y = ev.ScreenPos.y - 2; clipRect.width = 4; clipRect.height = 4; Cursor.ClipToRect(clipRect); } } }
/// <summary> /// Triggered when the user presses a mouse button. /// </summary> /// <param name="ev">Information about the mouse press event.</param> private void OnPointerPressed(PointerEvent ev) { guiCurveEditor.OnPointerPressed(ev); if (ev.button == PointerButton.Middle) { Vector2I windowPos = ScreenToWindowPos(ev.ScreenPos); Vector2 curvePos; if (guiCurveEditor.WindowToCurveSpace(windowPos, out curvePos)) { dragStartPos = windowPos; isButtonHeld = true; } } }
/// <summary> /// Triggered when the pointer is released. /// </summary> /// <param name="ev">Data about the pointer release event.</param> void Input_OnPointerReleased(PointerEvent ev) { if (isLocalDragInProgress) triggerEndLocalDrag = true; isLocalDragInProgress = false; isMouseDown = false; isDragInBounds = false; triggerStartLocalDrag = false; }
/// <summary> /// Triggers when some pointing device (mouse cursor, touch) button is double clicked. /// </summary> /// <param name="screenPos">Screen position where the input event occurred.</param> /// <param name="delta">Change in movement since last sent event.</param> /// <param name="button">Button that triggered the pointer event. Might be irrelevant depending on event type. /// (for example move events don't correspond to a button.</param> /// <param name="shift">Is shift button on the keyboard being held down.</param> /// <param name="ctrl">Is control button on the keyboard being held down.</param> /// <param name="alt">Is alt button on the keyboard being held down.</param> /// <param name="scrollAmount">If mouse wheel is being scrolled, what is the amount. Only relevant for /// move events.</param> /// <param name="isUsed">Set to true if the event was handled previously by some internal system (like GUI).</param> private static void Internal_TriggerPointerDoubleClick(Vector2I screenPos, Vector2I delta, PointerButton button, bool shift, bool ctrl, bool alt, float scrollAmount, bool isUsed) { PointerEvent ev = new PointerEvent(screenPos, delta, button, shift, ctrl, alt, scrollAmount, isUsed); if (OnPointerDoubleClick != null) OnPointerDoubleClick(ev); }
/// <summary> /// Triggered when the pointer is pressed. /// </summary> /// <param name="ev">Data about the pointer press event.</param> void Input_OnPointerPressed(PointerEvent ev) { Vector2I currentWindowPos = parentWindow.ScreenToWindowPos(ev.ScreenPos); if (Bounds.Contains(currentWindowPos)) { isMouseDown = true; mouseDownScreenPos = ev.ScreenPos; } }
/// <summary> /// Triggered when the pointer moved. /// </summary> /// <param name="ev">Data about the pointer move event.</param> void Input_OnPointerMoved(PointerEvent ev) { Vector2I currentWindowPos = parentWindow.ScreenToWindowPos(ev.ScreenPos); if (isMouseDown && !isLocalDragInProgress) { Vector2I startWindowPos = parentWindow.ScreenToWindowPos(mouseDownScreenPos); if (!Bounds.Contains(startWindowPos)) return; int distance = Vector2I.Distance(startWindowPos, currentWindowPos); if (distance >= DragStartDistancePx) triggerStartLocalDrag = true; } }
/// <summary> /// Handles input. Should be called by the owning window whenever a pointer is released. /// </summary> /// <param name="ev">Object containing pointer release event information.</param> internal void OnPointerReleased(PointerEvent ev) { if (isModifiedDuringDrag) OnCurveModified?.Invoke(); isPointerHeld = false; isDragInProgress = false; isMousePressedOverKey = false; isMousePressedOverTangent = false; isModifiedDuringDrag = false; }
/// <summary> /// Handles input. Should be called by the owning window whenever a pointer is pressed. /// </summary> /// <param name="ev">Object containing pointer press event information.</param> internal void OnPointerPressed(PointerEvent ev) { if (ev.IsUsed) return; Vector2I windowPos = window.ScreenToWindowPos(ev.ScreenPos); Rect2I elementBounds = GUIUtility.CalculateBounds(gui, window.GUI); Vector2I pointerPos = windowPos - new Vector2I(elementBounds.x, elementBounds.y); bool isOverEditor = pointerPos.x >= 0 && pointerPos.x < width && pointerPos.y >= 0 && pointerPos.y < height; if (!isOverEditor) return; else OnClicked?.Invoke(); Rect2I drawingBounds = drawingPanel.Bounds; Vector2I drawingPos = pointerPos - new Vector2I(drawingBounds.x, drawingBounds.y); Rect2I eventBounds = eventsPanel.Bounds; Vector2I eventPos = pointerPos - new Vector2I(eventBounds.x, eventBounds.y); if (ev.Button == PointerButton.Left) { Vector2 curveCoord; if (guiCurveDrawing.PixelToCurveSpace(drawingPos, out curveCoord, true)) { KeyframeRef keyframeRef; if (!guiCurveDrawing.FindKeyFrame(drawingPos, out keyframeRef)) { TangentRef tangentRef; if (guiCurveDrawing.FindTangent(drawingPos, out tangentRef)) { isMousePressedOverTangent = true; dragStart = drawingPos; draggedTangent = tangentRef; } else ClearSelection(); } else { if (!IsSelected(keyframeRef)) { if (!Input.IsButtonHeld(ButtonCode.LeftShift) && !Input.IsButtonHeld(ButtonCode.RightShift)) ClearSelection(); SelectKeyframe(keyframeRef); } isMousePressedOverKey = true; dragStart = drawingPos; } guiCurveDrawing.Rebuild(); UpdateEventsGUI(); } else { int frameIdx = guiTimeline.GetFrame(pointerPos); if (frameIdx != -1) SetMarkedFrame(frameIdx); else { int eventIdx; if (guiEvents.FindEvent(eventPos, out eventIdx)) { if (!Input.IsButtonHeld(ButtonCode.LeftShift) && !Input.IsButtonHeld(ButtonCode.RightShift)) ClearSelection(); events[eventIdx].selected = true; UpdateEventsGUI(); } else { ClearSelection(); guiCurveDrawing.Rebuild(); UpdateEventsGUI(); } } OnFrameSelected?.Invoke(frameIdx); } isPointerHeld = true; } else if (ev.Button == PointerButton.Right) { Vector2 curveCoord; if (guiCurveDrawing.PixelToCurveSpace(drawingPos, out curveCoord, true)) { contextClickPosition = drawingPos; KeyframeRef keyframeRef; if (!guiCurveDrawing.FindKeyFrame(drawingPos, out keyframeRef)) { ClearSelection(); blankContextMenu.Open(pointerPos, gui); guiCurveDrawing.Rebuild(); UpdateEventsGUI(); } else { // If clicked outside of current selection, just select the one keyframe if (!IsSelected(keyframeRef)) { ClearSelection(); SelectKeyframe(keyframeRef); guiCurveDrawing.Rebuild(); UpdateEventsGUI(); } keyframeContextMenu.Open(pointerPos, gui); } } else if (guiEvents.GetFrame(eventPos) != -1) // Clicked over events bar { contextClickPosition = eventPos; int eventIdx; if (!guiEvents.FindEvent(eventPos, out eventIdx)) { ClearSelection(); blankEventContextMenu.Open(pointerPos, gui); guiCurveDrawing.Rebuild(); UpdateEventsGUI(); } else { // If clicked outside of current selection, just select the one event if (!events[eventIdx].selected) { ClearSelection(); events[eventIdx].selected = true; guiCurveDrawing.Rebuild(); UpdateEventsGUI(); } eventContextMenu.Open(pointerPos, gui); } } } }
/// <summary> /// Handles input. Should be called by the owning window whenever a pointer is moved. /// </summary> /// <param name="ev">Object containing pointer move event information.</param> internal void OnPointerMoved(PointerEvent ev) { if (ev.Button != PointerButton.Left) return; if (isPointerHeld) { Vector2I windowPos = window.ScreenToWindowPos(ev.ScreenPos); Rect2I elementBounds = GUIUtility.CalculateBounds(gui, window.GUI); Vector2I pointerPos = windowPos - new Vector2I(elementBounds.x, elementBounds.y); if (isMousePressedOverKey || isMousePressedOverTangent) { Rect2I drawingBounds = drawingPanel.Bounds; Vector2I drawingPos = pointerPos - new Vector2I(drawingBounds.x, drawingBounds.y); if (!isDragInProgress) { int distance = Vector2I.Distance(drawingPos, dragStart); if (distance >= DRAG_START_DISTANCE) { if (isMousePressedOverKey && !disableCurveEdit) { draggedKeyframes.Clear(); foreach (var selectedEntry in selectedKeyframes) { EdAnimationCurve curve = curveInfos[selectedEntry.curveIdx].curve; KeyFrame[] keyFrames = curve.KeyFrames; DraggedKeyframes newEntry = new DraggedKeyframes(); newEntry.curveIdx = selectedEntry.curveIdx; draggedKeyframes.Add(newEntry); foreach (var keyframeIdx in selectedEntry.keyIndices) newEntry.keys.Add(new DraggedKeyframe(keyframeIdx, keyFrames[keyframeIdx])); } } isDragInProgress = true; } } if (isDragInProgress) { if (isMousePressedOverKey && !disableCurveEdit) { Vector2 diff = Vector2.Zero; Vector2 dragStartCurve; if (guiCurveDrawing.PixelToCurveSpace(dragStart, out dragStartCurve, true)) { Vector2 currentPosCurve; if (guiCurveDrawing.PixelToCurveSpace(drawingPos, out currentPosCurve, true)) diff = currentPosCurve - dragStartCurve; } foreach (var draggedEntry in draggedKeyframes) { EdAnimationCurve curve = curveInfos[draggedEntry.curveIdx].curve; for (int i = 0; i < draggedEntry.keys.Count; i++) { DraggedKeyframe draggedKey = draggedEntry.keys[i]; float newTime = Math.Max(0.0f, draggedKey.original.time + diff.x); float newValue = draggedKey.original.value + diff.y; int newIndex = curve.UpdateKeyframe(draggedKey.index, newTime, newValue); // It's possible key changed position due to time change, but since we're moving all // keys at once they cannot change position relative to one another, otherwise we would // need to update indices for other keys as well. draggedKey.index = newIndex; draggedEntry.keys[i] = draggedKey; } curve.Apply(); } // Rebuild selected keys from dragged keys (after potential sorting) ClearSelection(); foreach (var draggedEntry in draggedKeyframes) { foreach (var keyframe in draggedEntry.keys) SelectKeyframe(new KeyframeRef(draggedEntry.curveIdx, keyframe.index)); } isModifiedDuringDrag = true; window.RecordClipState(); guiCurveDrawing.Rebuild(); UpdateEventsGUI(); } else if (isMousePressedOverTangent && !disableCurveEdit) { EdAnimationCurve curve = curveInfos[draggedTangent.keyframeRef.curveIdx].curve; KeyFrame keyframe = curve.KeyFrames[draggedTangent.keyframeRef.keyIdx]; Vector2 keyframeCurveCoords = new Vector2(keyframe.time, keyframe.value); Vector2 currentPosCurve; if (guiCurveDrawing.PixelToCurveSpace(drawingPos, out currentPosCurve, true)) { Vector2 normal = currentPosCurve - keyframeCurveCoords; normal = normal.Normalized; float tangent = EdAnimationCurve.NormalToTangent(normal); if (draggedTangent.type == TangentType.In) { if (normal.x > 0.0f) tangent = float.PositiveInfinity; keyframe.inTangent = -tangent; if(curve.TangentModes[draggedTangent.keyframeRef.keyIdx] == TangentMode.Free) keyframe.outTangent = -tangent; } else { if (normal.x < 0.0f) tangent = float.PositiveInfinity; keyframe.outTangent = tangent; if (curve.TangentModes[draggedTangent.keyframeRef.keyIdx] == TangentMode.Free) keyframe.inTangent = tangent; } curve.KeyFrames[draggedTangent.keyframeRef.keyIdx] = keyframe; curve.Apply(); isModifiedDuringDrag = true; window.RecordClipState(); guiCurveDrawing.Rebuild(); } } } } else // Move frame marker { int frameIdx = guiTimeline.GetFrame(pointerPos); if (frameIdx != -1) SetMarkedFrame(frameIdx); OnFrameSelected?.Invoke(frameIdx); } } }