AnimationDataViewModel.cs 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. using System.Collections.ObjectModel;
  2. using System.Collections.Specialized;
  3. using CommunityToolkit.Mvvm.ComponentModel;
  4. using PixiEditor.AnimationRenderer.Core;
  5. using PixiEditor.AvaloniaUI.Models.DocumentModels;
  6. using PixiEditor.AvaloniaUI.Models.DocumentPassthroughActions;
  7. using PixiEditor.AvaloniaUI.Models.Handlers;
  8. using PixiEditor.ChangeableDocument.Actions.Generated;
  9. using PixiEditor.ChangeableDocument.Changeables.Animations;
  10. using PixiEditor.ChangeableDocument.Changeables.Interfaces;
  11. namespace PixiEditor.AvaloniaUI.ViewModels.Document;
  12. internal class AnimationDataViewModel : ObservableObject, IAnimationHandler
  13. {
  14. private int _activeFrameBindable = 1;
  15. private int _frameRate = 60;
  16. public DocumentViewModel Document { get; }
  17. protected DocumentInternalParts Internals { get; }
  18. public IReadOnlyCollection<IKeyFrameHandler> KeyFrames => keyFrames;
  19. private KeyFrameCollection keyFrames = new KeyFrameCollection();
  20. public int ActiveFrameBindable
  21. {
  22. get => _activeFrameBindable;
  23. set
  24. {
  25. if (Document.UpdateableChangeActive)
  26. return;
  27. Internals.ActionAccumulator.AddActions(new SetActiveFrame_PassthroughAction(value));
  28. }
  29. }
  30. public IAnimationRenderer Renderer { get; set; }
  31. public int FrameRate
  32. {
  33. get => _frameRate;
  34. set
  35. {
  36. _frameRate = value;
  37. OnPropertyChanged(nameof(FrameRate));
  38. OnPropertyChanged(nameof(DefaultEndFrame));
  39. }
  40. }
  41. public int FirstFrame => keyFrames.Count > 0 ? keyFrames.Min(x => x.StartFrameBindable) : 0;
  42. public int LastFrame => keyFrames.Count > 0 ? keyFrames.Max(x => x.StartFrameBindable + x.DurationBindable)
  43. : DefaultEndFrame;
  44. public int FramesCount => LastFrame - FirstFrame + 1;
  45. private double ActiveNormalizedTime => (double)(ActiveFrameBindable - FirstFrame) / FramesCount;
  46. private int DefaultEndFrame => FrameRate; // 1 second
  47. public AnimationDataViewModel(DocumentViewModel document, DocumentInternalParts internals)
  48. {
  49. Document = document;
  50. Internals = internals;
  51. }
  52. public KeyFrameTime ActiveFrameTime => new KeyFrameTime(ActiveFrameBindable, ActiveNormalizedTime);
  53. public void CreateRasterKeyFrame(Guid targetLayerGuid, int frame, Guid? toCloneFrom = null, int? frameToCopyFrom = null)
  54. {
  55. if (!Document.UpdateableChangeActive)
  56. {
  57. Internals.ActionAccumulator.AddFinishedActions(new CreateRasterKeyFrame_Action(targetLayerGuid, Guid.NewGuid(), frame,
  58. frameToCopyFrom ?? -1, toCloneFrom ?? Guid.Empty));
  59. }
  60. }
  61. public void DeleteKeyFrames(List<Guid> keyFrameIds)
  62. {
  63. if (!Document.UpdateableChangeActive)
  64. {
  65. for (var i = 0; i < keyFrameIds.Count; i++)
  66. {
  67. var id = keyFrameIds[i];
  68. if(i == keyFrameIds.Count - 1)
  69. {
  70. Internals.ActionAccumulator.AddFinishedActions(new DeleteKeyFrame_Action(id));
  71. }
  72. else
  73. {
  74. Internals.ActionAccumulator.AddActions(new DeleteKeyFrame_Action(id));
  75. }
  76. }
  77. }
  78. }
  79. public void ChangeKeyFramesStartPos(Guid[] infoIds, int infoDelta)
  80. {
  81. if (!Document.UpdateableChangeActive)
  82. {
  83. Internals.ActionAccumulator.AddActions(new KeyFramesStartPos_Action(infoIds.ToList(), infoDelta));
  84. }
  85. }
  86. public void EndKeyFramesStartPos()
  87. {
  88. if (!Document.UpdateableChangeActive)
  89. {
  90. Internals.ActionAccumulator.AddFinishedActions(new EndKeyFramesStartPos_Action());
  91. }
  92. }
  93. public void SetActiveFrame(int newFrame)
  94. {
  95. _activeFrameBindable = newFrame;
  96. OnPropertyChanged(nameof(ActiveFrameBindable));
  97. }
  98. public void SetFrameLength(Guid keyFrameId, int newStartFrame, int newDuration)
  99. {
  100. if(TryFindKeyFrame(keyFrameId, out KeyFrameViewModel keyFrame))
  101. {
  102. keyFrame.SetStartFrame(newStartFrame);
  103. keyFrame.SetDuration(newDuration);
  104. keyFrames.NotifyCollectionChanged();
  105. }
  106. }
  107. public void SetKeyFrameVisibility(Guid keyFrameId, bool isVisible)
  108. {
  109. if(TryFindKeyFrame(keyFrameId, out KeyFrameViewModel keyFrame))
  110. {
  111. keyFrame.SetVisibility(isVisible);
  112. keyFrames.NotifyCollectionChanged();
  113. }
  114. }
  115. public void AddKeyFrame(IKeyFrameHandler keyFrame)
  116. {
  117. Guid id = keyFrame.LayerGuid;
  118. if (TryFindKeyFrame(id, out KeyFrameGroupViewModel foundGroup))
  119. {
  120. foundGroup.Children.Add((KeyFrameViewModel)keyFrame);
  121. }
  122. else
  123. {
  124. var group =
  125. new KeyFrameGroupViewModel(keyFrame.StartFrameBindable, keyFrame.DurationBindable, id, id, Document, Internals);
  126. group.Children.Add((KeyFrameViewModel)keyFrame);
  127. keyFrames.Add(group);
  128. }
  129. keyFrames.NotifyCollectionChanged(NotifyCollectionChangedAction.Add, (KeyFrameViewModel)keyFrame);
  130. }
  131. public void RemoveKeyFrame(Guid keyFrameId)
  132. {
  133. TryFindKeyFrame<KeyFrameViewModel>(keyFrameId, out _, (frame, parent) =>
  134. {
  135. parent.Children.Remove(frame);
  136. keyFrames.NotifyCollectionChanged(NotifyCollectionChangedAction.Remove, (KeyFrameViewModel)frame);
  137. });
  138. }
  139. public void AddSelectedKeyFrame(Guid keyFrameId)
  140. {
  141. if (TryFindKeyFrame(keyFrameId, out KeyFrameViewModel keyFrame))
  142. {
  143. keyFrame.IsSelected = true;
  144. }
  145. }
  146. public void RemoveSelectedKeyFrame(Guid keyFrameId)
  147. {
  148. if (TryFindKeyFrame(keyFrameId, out KeyFrameViewModel keyFrame))
  149. {
  150. keyFrame.IsSelected = false;
  151. }
  152. }
  153. public void ClearSelectedKeyFrames()
  154. {
  155. var selectedFrames = keyFrames.SelectChildrenBy<KeyFrameViewModel>(x => x.IsSelected);
  156. foreach (var frame in selectedFrames)
  157. {
  158. frame.IsSelected = false;
  159. }
  160. }
  161. public void RemoveKeyFrames(List<Guid> keyFrameIds)
  162. {
  163. List<KeyFrameViewModel> framesToRemove = new List<KeyFrameViewModel>();
  164. foreach (var keyFrame in keyFrameIds)
  165. {
  166. TryFindKeyFrame<KeyFrameViewModel>(keyFrame, out _, (frame, parent) =>
  167. {
  168. parent.Children.Remove(frame);
  169. framesToRemove.Add((KeyFrameViewModel)frame);
  170. });
  171. }
  172. keyFrames.NotifyCollectionChanged(NotifyCollectionChangedAction.Remove, framesToRemove);
  173. }
  174. public bool FindKeyFrame<T>(Guid guid, out T keyFrameHandler) where T : IKeyFrameHandler
  175. {
  176. return TryFindKeyFrame<T>(keyFrames, null, guid, out keyFrameHandler, null);
  177. }
  178. // TODO: Use the same structure functions as layers
  179. public bool TryFindKeyFrame<T>(Guid id, out T? foundKeyFrame,
  180. Action<IKeyFrameHandler, IKeyFrameGroupHandler?> onFound = null) where T : IKeyFrameHandler
  181. {
  182. return TryFindKeyFrame(keyFrames, null, id, out foundKeyFrame, onFound);
  183. }
  184. private bool TryFindKeyFrame<T>(IReadOnlyCollection<IKeyFrameHandler> root, IKeyFrameGroupHandler parent, Guid id, out T? result,
  185. Action<IKeyFrameHandler, IKeyFrameGroupHandler?> onFound) where T : IKeyFrameHandler
  186. {
  187. for (var i = 0; i < root.Count; i++)
  188. {
  189. var frame = root.ElementAt(i);
  190. if (frame is T targetFrame && targetFrame.Id.Equals(id))
  191. {
  192. result = targetFrame;
  193. onFound?.Invoke(frame, parent);
  194. return true;
  195. }
  196. if (frame is IKeyFrameGroupHandler { Children.Count: > 0 } group)
  197. {
  198. bool found = TryFindKeyFrame(group.Children, group, id, out result, onFound);
  199. if (found)
  200. {
  201. return true;
  202. }
  203. }
  204. }
  205. result = default;
  206. return false;
  207. }
  208. }