Browse Source

Fixed changing length

flabbet 1 year ago
parent
commit
8fa8d81a5f

+ 1 - 1
src/PixiEditor.AvaloniaUI/ViewModels/Document/AnimationDataViewModel.cs

@@ -46,7 +46,7 @@ internal class AnimationDataViewModel : ObservableObject, IAnimationHandler
 
     public int FirstFrame => keyFrames.Count > 0 ? keyFrames.Min(x => x.StartFrameBindable) : 0;
     public int LastFrame => keyFrames.Count > 0 ? keyFrames.Max(x => x.StartFrameBindable + x.DurationBindable) : 0;
-    public int FramesCount => LastFrame - FirstFrame; 
+    public int FramesCount => LastFrame - FirstFrame + 1; 
 
     public AnimationDataViewModel(DocumentViewModel document, DocumentInternalParts internals)
     {

+ 3 - 3
src/PixiEditor.AvaloniaUI/Views/Animations/KeyFrame.cs

@@ -148,14 +148,14 @@ internal class KeyFrame : TemplatedControl
         int frame;
         if (round)
         {
-            frame = (int)Math.Round(x / Scale);
+            frame = (int)Math.Round(x / Scale) + 1;
         }
         else
         {
-            frame = (int)Math.Floor(x / Scale);
+            frame = (int)Math.Floor(x / Scale) + 1;
         }
         
-        frame = Math.Max(0, frame);
+        frame = Math.Max(1, frame);
         return frame;
     }
     

+ 3 - 3
src/PixiEditor.AvaloniaUI/Views/Animations/Timeline.cs

@@ -323,7 +323,7 @@ internal class Timeline : TemplatedControl, INotifyPropertyChanged
 
     private void PlayTimerOnTick(object? sender, EventArgs e)
     {
-        if (ActiveFrame >= KeyFrames.FrameCount + 1)
+        if (ActiveFrame >= KeyFrames.FrameCount)
         {
             ActiveFrame = 1;
         }
@@ -505,11 +505,11 @@ internal class Timeline : TemplatedControl, INotifyPropertyChanged
         int frame;
         if (round)
         {
-            frame = (int)Math.Round(x / Scale);
+            frame = (int)Math.Round(x / Scale) + 1;
         }
         else
         {
-            frame = (int)Math.Floor(x / Scale);
+            frame = (int)Math.Floor(x / Scale) + 1;
         }
 
         frame = Math.Max(1, frame);

+ 2 - 1
src/PixiEditor.ChangeableDocument/Changeables/Animations/AnimationData.cs

@@ -23,7 +23,8 @@ internal class AnimationData : IReadOnlyAnimationData
         }
         else
         {
-            GroupKeyFrame createdGroup = new GroupKeyFrame(id, keyFrame.StartFrame, document);
+            var layer = document.FindMemberOrThrow<Layer>(id);
+            GroupKeyFrame createdGroup = new GroupKeyFrame(layer, keyFrame.StartFrame, document);
             createdGroup.Children.Add(keyFrame);
             keyFrames.Add(createdGroup);
         }

+ 3 - 16
src/PixiEditor.ChangeableDocument/Changeables/Animations/GroupKeyFrame.cs

@@ -14,28 +14,15 @@ internal class GroupKeyFrame : KeyFrame, IKeyFrameChildrenContainer
 
     IReadOnlyList<IReadOnlyKeyFrame> IKeyFrameChildrenContainer.Children => Children;
 
-    public GroupKeyFrame(Guid layerGuid, int startFrame, Document document) : base(layerGuid, startFrame)
+    public GroupKeyFrame(IReadOnlyLayer layer, int startFrame, Document document) : base(layer, startFrame)
     {
-        Id = layerGuid;
+        Id = layer.GuidValue;
         this.document = document;
     }
 
-    protected override void OnVisibilityChanged()
-    {
-        foreach (var child in Children)
-        {
-            child.IsVisible = IsVisible;
-        }
-    }
-
-    public override bool IsWithinRange(int frame)
-    {
-        return frame >= StartFrame && frame < EndFrame + 1;
-    }
-
     public override KeyFrame Clone()
     {
-        var clone = new GroupKeyFrame(LayerGuid, StartFrame, document) { Id = this.Id };
+        var clone = new GroupKeyFrame(TargetLayer, StartFrame, document) { Id = this.Id };
         foreach (var child in Children)
         {
             clone.Children.Add(child.Clone());

+ 8 - 13
src/PixiEditor.ChangeableDocument/Changeables/Animations/KeyFrame.cs

@@ -2,7 +2,7 @@
 
 namespace PixiEditor.ChangeableDocument.Changeables.Animations;
 
-public abstract class KeyFrame : IReadOnlyKeyFrame, IDisposable
+public abstract class KeyFrame : IReadOnlyKeyFrame
 {
     private int startFrame;
     private int duration;
@@ -19,6 +19,7 @@ public abstract class KeyFrame : IReadOnlyKeyFrame, IDisposable
             }
 
             startFrame = value;
+            TargetLayer.SetKeyFrameLength(Id, startFrame, Duration);
         }
     }
 
@@ -33,6 +34,7 @@ public abstract class KeyFrame : IReadOnlyKeyFrame, IDisposable
             }
 
             duration = value;
+            TargetLayer.SetKeyFrameLength(Id, StartFrame, Duration);
         }
     }
     
@@ -47,26 +49,19 @@ public abstract class KeyFrame : IReadOnlyKeyFrame, IDisposable
         set
         {
             isVisible = value;
-            OnVisibilityChanged();
         }
     }
 
-    protected KeyFrame(Guid layerGuid, int startFrame)
+    public IReadOnlyLayer TargetLayer { get; }
+
+    protected KeyFrame(IReadOnlyLayer layer, int startFrame)
     {
-        LayerGuid = layerGuid;
+        TargetLayer = layer;
+        LayerGuid = layer.GuidValue;
         this.startFrame = startFrame;
         duration = 1;
         Id = Guid.NewGuid();
     }
     
-    public virtual bool IsWithinRange(int frame)
-    {
-        return frame >= StartFrame && frame < EndFrame;
-    }
-
     public abstract KeyFrame Clone();
-
-    public virtual void Dispose() { }
-    
-    protected virtual void OnVisibilityChanged() { }
 }

+ 1 - 5
src/PixiEditor.ChangeableDocument/Changeables/Animations/RasterKeyFrame.cs

@@ -10,7 +10,7 @@ internal class RasterKeyFrame : KeyFrame, IReadOnlyRasterKeyFrame
     private ChunkyImage targetImage;
     
     public RasterKeyFrame(Guid id, RasterLayer layer, int startFrame, Document document, ChunkyImage? cloneFrom = null)
-        : base(layer.GuidValue, startFrame)
+        : base(layer, startFrame)
     {
         Id = id;
         targetLayer = layer;
@@ -26,9 +26,5 @@ internal class RasterKeyFrame : KeyFrame, IReadOnlyRasterKeyFrame
         return new RasterKeyFrame(Id, targetLayer, StartFrame, Document, image);
     }
 
-    public override void Dispose()
-    {
-    }
-
     public IReadOnlyChunkyImage Image => targetImage;
 }

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changeables/Interfaces/IReadOnlyKeyFrame.cs

@@ -7,4 +7,5 @@ public interface IReadOnlyKeyFrame
     public Guid LayerGuid { get; }
     public Guid Id { get; }
     public bool IsVisible { get; }
+    public IReadOnlyLayer TargetLayer { get; }
 }

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changeables/Interfaces/IReadOnlyLayer.cs

@@ -7,4 +7,5 @@ public interface IReadOnlyLayer : IReadOnlyStructureMember
 {
     public ChunkyImage Rasterize(KeyFrameTime frameTime);
     public void RemoveKeyFrame(Guid keyFrameGuid);
+    public void SetKeyFrameLength(Guid keyFrameGuid, int startFrame, int duration);
 }

+ 1 - 0
src/PixiEditor.ChangeableDocument/Changeables/Layer.cs

@@ -8,4 +8,5 @@ internal abstract class Layer : StructureMember, IReadOnlyLayer
 {
     public abstract ChunkyImage Rasterize(KeyFrameTime frameTime);
     public abstract void RemoveKeyFrame(Guid keyFrameGuid);
+    public abstract void SetKeyFrameLength(Guid keyFrameGuid, int startFrame, int duration);
 }

+ 30 - 6
src/PixiEditor.ChangeableDocument/Changeables/RasterLayer.cs

@@ -36,11 +36,25 @@ internal class RasterLayer : Layer, IReadOnlyRasterLayer
     }
 
     IReadOnlyChunkyImage IReadOnlyRasterLayer.GetLayerImageAtFrame(int frame) => GetLayerImageAtFrame(frame);
-    IReadOnlyChunkyImage IReadOnlyRasterLayer.GetLayerImageByKeyFrameGuid(Guid keyFrameGuid) => GetLayerImageByKeyFrameGuid(keyFrameGuid);
-    void IReadOnlyRasterLayer.SetLayerImageAtFrame(int frame, IReadOnlyChunkyImage newLayerImage) => SetLayerImageAtFrame(frame, (ChunkyImage)newLayerImage);
+
+    IReadOnlyChunkyImage IReadOnlyRasterLayer.GetLayerImageByKeyFrameGuid(Guid keyFrameGuid) =>
+        GetLayerImageByKeyFrameGuid(keyFrameGuid);
+
+    void IReadOnlyRasterLayer.SetLayerImageAtFrame(int frame, IReadOnlyChunkyImage newLayerImage) =>
+        SetLayerImageAtFrame(frame, (ChunkyImage)newLayerImage);
 
     void IReadOnlyRasterLayer.ForEveryFrame(Action<IReadOnlyChunkyImage> action) => ForEveryFrame(action);
 
+    public override void SetKeyFrameLength(Guid keyFrameGuid, int startFrame, int duration)
+    {
+        ImageFrame frame = frameImages.FirstOrDefault(x => x.KeyFrameGuid == keyFrameGuid);
+        if (frame is not null)
+        {
+            frame.StartFrame = startFrame;
+            frame.Duration = duration;
+        }
+    }
+
     public void ForEveryFrame(Action<ChunkyImage> action)
     {
         foreach (var frame in frameImages)
@@ -53,7 +67,7 @@ internal class RasterLayer : Layer, IReadOnlyRasterLayer
     {
         return Rasterize(frame);
     }
-    
+
     public ChunkyImage GetLayerImageByKeyFrameGuid(Guid keyFrameGuid)
     {
         return frameImages.FirstOrDefault(x => x.KeyFrameGuid == keyFrameGuid)?.Image ?? frameImages[0].Image;
@@ -68,6 +82,15 @@ internal class RasterLayer : Layer, IReadOnlyRasterLayer
 
         ImageFrame frame = frameImages.FirstOrDefault(x => x.IsInFrame(frameTime.Frame));
 
+        if (frame == null)
+        {
+            ImageFrame lastFrame = frameImages.MaxBy(x => x.StartFrame + x.Duration);
+            if (frameTime.Frame == lastFrame.StartFrame + lastFrame.Duration)
+            {
+                return lastFrame.Image;
+            }
+        }
+
         return frame?.Image ?? frameImages[0].Image;
     }
 
@@ -90,9 +113,10 @@ internal class RasterLayer : Layer, IReadOnlyRasterLayer
         List<ImageFrame> clonedFrames = new();
         foreach (var frame in frameImages)
         {
-            clonedFrames.Add(new ImageFrame(frame.KeyFrameGuid, frame.StartFrame, frame.Duration, frame.Image.CloneFromCommitted()));
+            clonedFrames.Add(new ImageFrame(frame.KeyFrameGuid, frame.StartFrame, frame.Duration,
+                frame.Image.CloneFromCommitted()));
         }
-        
+
         return new RasterLayer(clonedFrames)
         {
             GuidValue = GuidValue,
@@ -130,7 +154,7 @@ class ImageFrame
     public int StartFrame { get; set; }
     public int Duration { get; set; }
     public ChunkyImage Image { get; set; }
-    
+
     public Guid KeyFrameGuid { get; set; }
 
     public ImageFrame(Guid keyFrameGuid, int startFrame, int duration, ChunkyImage image)

+ 0 - 5
src/PixiEditor.ChangeableDocument/Changes/Animation/DeleteKeyFrame_Change.cs

@@ -38,9 +38,4 @@ internal class DeleteKeyFrame_Change : Change
         target.AnimationData.AddKeyFrame(clonedKeyFrame.Clone());
         return new CreateRasterKeyFrame_ChangeInfo(clonedKeyFrame.LayerGuid, clonedKeyFrame.StartFrame, clonedKeyFrame.Id, false);   
     }
-
-    public override void Dispose()
-    {
-        clonedKeyFrame.Dispose();
-    }
 }