浏览代码

playback fps

flabbet 1 年之前
父节点
当前提交
85d121c775

+ 5 - 9
src/PixiEditor.AvaloniaUI/Styles/Templates/Timeline.axaml

@@ -7,7 +7,8 @@
                     xmlns:commands="clr-namespace:PixiEditor.AvaloniaUI.Models.Commands.Attributes.Commands"
                     xmlns:xaml="clr-namespace:PixiEditor.AvaloniaUI.Models.Commands.XAML"
                     xmlns:converters="clr-namespace:PixiEditor.AvaloniaUI.Helpers.Converters"
-                    xmlns:ui="clr-namespace:PixiEditor.AvaloniaUI.Helpers.UI">
+                    xmlns:ui="clr-namespace:PixiEditor.AvaloniaUI.Helpers.UI"
+                    xmlns:input="clr-namespace:PixiEditor.AvaloniaUI.Views.Input">
     <Design.PreviewWith>
         <animations:Timeline>
             <animations:Timeline.KeyFrames>
@@ -41,6 +42,7 @@
                         <TextBlock DockPanel.Dock="Left" Text="Scale:" />
                         <Slider Minimum="1" Maximum="100" Value="{TemplateBinding Scale, Mode=TwoWay}" Width="100" />
                         <TextBlock Text="{Binding Scale, RelativeSource={RelativeSource TemplatedParent}}" />
+                        <input:NumberInput Min="1" Value="{Binding Fps, RelativeSource={RelativeSource TemplatedParent}, Mode=TwoWay}" />
                         <Panel>
                             <ToggleButton HorizontalAlignment="Center" Content="Play" Name="PART_PlayToggle" />
                         </Panel>
@@ -81,7 +83,7 @@
                                 <TreeView.ItemContainerTheme>
                                     <ControlTheme TargetType="TreeViewItem">
                                         <Setter Property="ClipToBounds" Value="False"/>
-                                        <Setter Property="Margin" Value="0 5"></Setter>
+                                        <Setter Property="Margin" Value="0, 5"/>
                                         <Setter Property="Template">
                                             <ControlTemplate>
                                                 <StackPanel Orientation="Horizontal">
@@ -107,7 +109,7 @@
                                 <TreeView.DataTemplates>
                                     <TreeDataTemplate DataType="document:KeyFrameGroupViewModel"
                                                       ItemsSource="{Binding Children}">
-                                        <Grid Width="200">
+                                        <Grid Width="200" Margin="0, 5">
                                             <TextBlock Text="{Binding StartFrameBindable}" />
                                         </Grid>
                                     </TreeDataTemplate>
@@ -121,12 +123,6 @@
                                                     <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType=animations:Timeline}" Path="Scale" />
                                                 </MultiBinding>
                                             </animations:KeyFrame.Width>
-                                            <animations:KeyFrame.Margin>
-                                                <MultiBinding Converter="{converters:DurationToMarginConverter}">
-                                                    <Binding Path="Item.StartFrameBindable" RelativeSource="{RelativeSource Self}" />
-                                                    <Binding RelativeSource="{RelativeSource FindAncestor, AncestorType=animations:Timeline}" Path="Scale" />
-                                                </MultiBinding>
-                                            </animations:KeyFrame.Margin>
                                         </animations:KeyFrame>
                                     </DataTemplate>
                                 </TreeView.DataTemplates>

+ 16 - 0
src/PixiEditor.AvaloniaUI/Views/Animations/KeyFrame.cs

@@ -2,8 +2,10 @@
 using Avalonia.Controls;
 using Avalonia.Controls.Metadata;
 using Avalonia.Controls.Primitives;
+using Avalonia.Data;
 using Avalonia.Input;
 using Avalonia.VisualTree;
+using PixiEditor.AvaloniaUI.Helpers.Converters;
 using PixiEditor.AvaloniaUI.ViewModels.Document;
 
 namespace PixiEditor.AvaloniaUI.Views.Animations;
@@ -52,6 +54,20 @@ internal class KeyFrame : TemplatedControl
         PointerPressed += CapturePointer;
         PointerMoved += DragOnPointerMoved;
         PointerCaptureLost += UpdateKeyFrame;
+
+        if (Item is not KeyFrameGroupViewModel)
+        {
+            MultiBinding marginBinding = new MultiBinding
+            {
+                Converter = new DurationToMarginConverter(),
+                Bindings =
+                {
+                    new Binding("StartFrameBindable") { Source = Item }, new Binding("Scale") { Source = this },
+                },
+            };
+
+            this.FindAncestorOfType<TreeViewItem>().Bind(MarginProperty, marginBinding);
+        }
     }
     
     private void CapturePointer(object? sender, PointerPressedEventArgs e)

+ 20 - 1
src/PixiEditor.AvaloniaUI/Views/Animations/Timeline.cs

@@ -29,6 +29,8 @@ internal class Timeline : TemplatedControl
 
     public static readonly StyledProperty<double> ScaleProperty = AvaloniaProperty.Register<Timeline, double>(
         nameof(Scale), 100);
+    
+    public static readonly StyledProperty<int> FpsProperty = AvaloniaProperty.Register<Timeline, int>(nameof(Fps), 60);
 
     public double Scale
     {
@@ -70,17 +72,24 @@ internal class Timeline : TemplatedControl
         set { SetValue(ActiveFrameProperty, value); }
     }
 
+    public int Fps
+    {
+        get { return (int)GetValue(FpsProperty); }
+        set { SetValue(FpsProperty, value); }
+    }
+
     private ToggleButton? _playToggle;
     private DispatcherTimer _playTimer;
 
     static Timeline()
     {
         IsPlayingProperty.Changed.Subscribe(IsPlayingChanged);
+        FpsProperty.Changed.Subscribe(FpsChanged);
     }
 
     public Timeline()
     {
-        _playTimer = new DispatcherTimer(DispatcherPriority.Render) { Interval = TimeSpan.FromMilliseconds(1000 / 8f) };
+        _playTimer = new DispatcherTimer(DispatcherPriority.Render) { Interval = TimeSpan.FromMilliseconds(1000f / Fps) };
         _playTimer.Tick += PlayTimerOnTick;
     }
 
@@ -150,4 +159,14 @@ internal class Timeline : TemplatedControl
             timeline._playTimer.Stop();
         }
     }
+    
+    private static void FpsChanged(AvaloniaPropertyChangedEventArgs e)
+    {
+        if (e.Sender is not Timeline timeline)
+        {
+            return;
+        }
+
+        timeline._playTimer.Interval = TimeSpan.FromMilliseconds(1000f / timeline.Fps);
+    }
 }