/// <summary> /// Removes all currently selected keyframes from the curves. /// </summary> private void DeleteSelectedKeyframes() { if (!disableCurveEdit) { foreach (var selectedEntry in selectedKeyframes) { EdAnimationCurve curve = curveInfos[selectedEntry.curveIdx].curve; // Sort keys from highest to lowest so the indices don't change selectedEntry.keyIndices.Sort((x, y) => { return(y.CompareTo(x)); }); foreach (var keyframeIdx in selectedEntry.keyIndices) { curve.RemoveKeyframe(keyframeIdx); } curve.Apply(); } } else { ShowReadOnlyMessage(); } // TODO - UNDOREDO ClearSelection(); OnCurveModified?.Invoke(); guiCurveDrawing.Rebuild(); UpdateEventsGUI(); }
/// <summary> /// Changes the tangent mode for all currently selected keyframes. /// </summary> /// <param name="mode">Tangent mode to set. If only in or out tangent mode is provided, the mode for the opposite /// tangent will be kept as is.</param> private void ChangeSelectionTangentMode(TangentMode mode) { if (disableCurveEdit) { ShowReadOnlyMessage(); return; } foreach (var selectedEntry in selectedKeyframes) { EdAnimationCurve curve = curveInfos[selectedEntry.curveIdx].curve; foreach (var keyframeIdx in selectedEntry.keyIndices) { if (mode == TangentMode.Auto || mode == TangentMode.Free) { curve.SetTangentMode(keyframeIdx, mode); } else { TangentMode newMode = curve.TangentModes[keyframeIdx]; if (mode.HasFlag((TangentMode)TangentType.In)) { // Replace only the in tangent mode, keeping the out tangent as is TangentMode inFlags = (TangentMode.InAuto | TangentMode.InFree | TangentMode.InLinear | TangentMode.InStep); newMode &= ~inFlags; newMode |= (mode & inFlags); } else { // Replace only the out tangent mode, keeping the in tangent as is TangentMode outFlags = (TangentMode.OutAuto | TangentMode.OutFree | TangentMode.OutLinear | TangentMode.OutStep); newMode &= ~outFlags; newMode |= (mode & outFlags); } curve.SetTangentMode(keyframeIdx, newMode); } } curve.Apply(); } // TODO - UNDOREDO OnCurveModified?.Invoke(); guiCurveDrawing.Rebuild(); }
/// <summary> /// Opens the edit window for the currently selected keyframe. /// </summary> private void EditSelectedKeyframe() { if (disableCurveEdit) { ShowReadOnlyMessage(); return; } if (selectedKeyframes.Count == 0) { return; } EdAnimationCurve curve = curveInfos[selectedKeyframes[0].curveIdx].curve; KeyFrame[] keyFrames = curve.KeyFrames; int keyIndex = selectedKeyframes[0].keyIndices[0]; KeyFrame keyFrame = keyFrames[keyIndex]; Vector2I position = guiCurveDrawing.CurveToPixelSpace(new Vector2(keyFrame.time, keyFrame.value)); Rect2I drawingBounds = GUIUtility.CalculateBounds(drawingPanel, window.GUI); position.x = MathEx.Clamp(position.x, 0, drawingBounds.width); position.y = MathEx.Clamp(position.y, 0, drawingBounds.height); Vector2I windowPos = position + new Vector2I(drawingBounds.x, drawingBounds.y); KeyframeEditWindow editWindow = DropDownWindow.Open <KeyframeEditWindow>(window, windowPos); editWindow.Initialize(keyFrame, x => { curve.UpdateKeyframe(keyIndex, x.time, x.value); curve.Apply(); // TODO UNDOREDO guiCurveDrawing.Rebuild(); OnCurveModified?.Invoke(); }); }
/// <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])); } } } // TODO - UNDOREDO record keyframe or tangent isDragInProgress = true; } } if (isDragInProgress) { if (isMousePressedOverKey && !disableCurveEdit) { Vector2 diff = Vector2.Zero; Vector2 dragStartCurve; if (guiCurveDrawing.PixelToCurveSpace(dragStart, out dragStartCurve)) { Vector2 currentPosCurve; if (guiCurveDrawing.PixelToCurveSpace(drawingPos, out currentPosCurve)) { 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 = 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)); } } OnCurveModified?.Invoke(); 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)) { 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(); OnCurveModified?.Invoke(); guiCurveDrawing.Rebuild(); } } } } else // Move frame marker { int frameIdx = guiTimeline.GetFrame(pointerPos); if (frameIdx != -1) { SetMarkedFrame(frameIdx); } OnFrameSelected?.Invoke(frameIdx); } } }