void SetKeyframe(bool value) { int currentFrame = Document.Current.AnimationFrame; foreach (var(animable, owner) in editorParams.RootObjects.Zip(editorParams.Objects, (ro, o) => (ro as IAnimationHost, o))) { bool hasKey = false; if (animable.Animators.TryFind(editorParams.PropertyPath, out IAnimator animator, Document.Current.AnimationId)) { hasKey = animator.ReadonlyKeys.Any(i => i.Frame == currentFrame); if (hasKey && !value) { Core.Operations.RemoveKeyframe.Perform(animator, currentFrame); } } if (!hasKey && value) { var propValue = editorParams.IndexInList == -1 ? new Property(owner, editorParams.PropertyName).Getter() : new IndexedProperty(owner, editorParams.PropertyName, editorParams.IndexInList).Getter(); var keyFunction = animator?.Keys.LastOrDefault(k => k.Frame <= currentFrame)?.Function ?? CoreUserPreferences.Instance.DefaultKeyFunction; IKeyframe keyframe = Keyframe.CreateForType(editorParams.PropertyInfo.PropertyType, currentFrame, propValue, keyFunction); Core.Operations.SetKeyframe.Perform(animable, editorParams.PropertyPath, Document.Current.AnimationId, keyframe); } } }
void SetKeyframe(bool value) { int currentFrame = Document.Current.AnimationFrame; foreach (var animable in editorParams.Objects.OfType <IAnimable>()) { IAnimator animator; bool hasKey = false; if (animable.Animators.TryFind(editorParams.PropertyName, out animator, Document.Current.AnimationId)) { hasKey = animator.ReadonlyKeys.Any(i => i.Frame == currentFrame); if (hasKey && !value) { Core.Operations.RemoveKeyframe.Perform(animator, currentFrame); } } if (!hasKey && value) { var propValue = new Property(animable, editorParams.PropertyName).Getter(); if (animator == null) { animator = AnimatorRegistry.Instance.CreateAnimator(editorParams.PropertyInfo.PropertyType); animator.TargetProperty = editorParams.PropertyName; animator.AnimationId = Document.Current.AnimationId; Core.Operations.SetAnimator.Perform(animable, animator); } var keyFunction = animator.Keys.LastOrDefault(k => k.Frame < currentFrame)?.Function ?? KeyFunction.Linear; IKeyframe keyframe = Keyframe.CreateForType(editorParams.PropertyInfo.PropertyType, currentFrame, propValue, keyFunction); Core.Operations.SetKeyframe.Perform(animable, editorParams.PropertyName, Document.Current.AnimationId, keyframe); } } }
public static void Perform(object @object, string propertyPath, object value, bool createAnimatorIfNeeded = false, bool createInitialKeyframeForNewAnimator = true, int atFrame = -1) { IAnimator animator; var animationHost = @object as IAnimationHost; object owner = @object; int index = -1; AnimationUtils.PropertyData propertyData = AnimationUtils.PropertyData.Empty; if (animationHost != null) { (propertyData, owner, index) = AnimationUtils.GetPropertyByPath(animationHost, propertyPath); } if (index == -1) { SetProperty.Perform(owner, propertyData.Info?.Name ?? propertyPath, value); } else { SetIndexedProperty.Perform(owner, propertyData.Info?.Name ?? propertyPath, index, value); } if (animationHost != null && (animationHost.Animators.TryFind(propertyPath, out animator, Document.Current.AnimationId) || createAnimatorIfNeeded)) { if (animator == null && createInitialKeyframeForNewAnimator) { var propertyValue = propertyData.Info.GetValue(owner); Perform(animationHost, propertyPath, propertyValue, true, false, 0); } int savedFrame = -1; if (atFrame >= 0 && Document.Current.AnimationFrame != atFrame) { savedFrame = Document.Current.AnimationFrame; Document.Current.AnimationFrame = atFrame; } try { var type = propertyData.Info.PropertyType; var key = animator?.ReadonlyKeys.GetByFrame(Document.Current.AnimationFrame)?.Clone() ?? Keyframe.CreateForType(type); key.Frame = Document.Current.AnimationFrame; key.Function = animator?.Keys.LastOrDefault(k => k.Frame <= key.Frame)?.Function ?? KeyFunction.Linear; key.Value = value; SetKeyframe.Perform(animationHost, propertyPath, Document.Current.AnimationId, key); } finally { if (savedFrame >= 0) { Document.Current.AnimationFrame = savedFrame; } } } }
public static void Perform(object @object, string propertyName, object value) { SetProperty.Perform(@object, propertyName, value); IAnimator animator; var animable = @object as IAnimable; if (animable != null && animable.Animators.TryFind(propertyName, out animator, Document.Current.AnimationId)) { var type = animable.GetType().GetProperty(propertyName).PropertyType; var key = animator.ReadonlyKeys.FirstOrDefault(i => i.Frame == Document.Current.AnimationFrame)?.Clone() ?? Keyframe.CreateForType(type); key.Frame = Document.Current.AnimationFrame; key.Function = animator.Keys.LastOrDefault(k => k.Frame < key.Frame)?.Function ?? KeyFunction.Linear; key.Value = value; SetKeyframe.Perform(animable, propertyName, Document.Current.AnimationId, key); } }
private void ShowContextMenu() { SelectAnimationBasedOnMousePosition(); var menu = new Menu(); var rootNode = Document.Current.RootNode; menu.Add(new Command("Add", () => AddAnimation(rootNode, false))); menu.Add(new Command("Add Compound", () => AddAnimation(rootNode, true))); menu.Add(new Command("Add ZeroPose", () => AddZeroPoseAnimation(rootNode)) { Enabled = !rootNode.Animations.TryFind(Animation.ZeroPoseId, out _) }); var path = GetNodePath(Document.Current.Container); if (!string.IsNullOrEmpty(path)) { var container = Document.Current.Container; menu.Add(new Command($"Add To '{path}'", () => AddAnimation(container, false))); menu.Add(new Command($"Add Compound To '{path}'", () => AddAnimation(container, true))); menu.Add(new Command($"Add ZeroPose To '{path}'", () => AddZeroPoseAnimation(container)) { Enabled = !container.Animations.TryFind(Animation.ZeroPoseId, out _) }); } menu.Add(Command.MenuSeparator); menu.Add(new Command("Rename", RenameAnimation)); menu.Add(new Command("Duplicate", DuplicateAnimation)); menu.Add(Command.Delete); menu.Popup(); void AddAnimation(Node node, bool compound) { Document.Current.History.DoTransaction(() => { var animation = new Animation { Id = GenerateAnimationId("NewAnimation"), IsCompound = compound }; Core.Operations.InsertIntoList.Perform(node.Animations, node.Animations.Count, animation); SelectAnimation(GetAnimations().IndexOf(animation)); if (compound) { var track = new AnimationTrack { Id = "Track1" }; Core.Operations.InsertIntoList <AnimationTrackList, AnimationTrack> .Perform(animation.Tracks, 0, track); } }); // Schedule animation rename on the next update, since the widgets are not built yet panelWidget.Tasks.Add(DelayedRenameAnimation()); } void AddZeroPoseAnimation(Node node) { Document.Current.History.DoTransaction(() => { var animation = new Animation { Id = Animation.ZeroPoseId }; InsertIntoList.Perform(node.Animations, node.Animations.Count, animation); foreach (var a in node.Descendants.SelectMany(n => n.Animators).ToList()) { var(propertyData, animable, index) = AnimationUtils.GetPropertyByPath(a.Owner, a.TargetPropertyPath); var zeroPoseKey = Keyframe.CreateForType(propertyData.Info.PropertyType); zeroPoseKey.Value = index == -1 ? propertyData.Info.GetValue(animable) : propertyData.Info.GetValue(animable, new object[] { index }); zeroPoseKey.Function = KeyFunction.Steep; SetKeyframe.Perform(a.Owner, a.TargetPropertyPath, Animation.ZeroPoseId, zeroPoseKey); } SelectAnimation(GetAnimations().IndexOf(animation)); }); } IEnumerator <object> DelayedRenameAnimation() { yield return(null); RenameAnimation(); } }