Browse Source
* Add AnimationSpeedPage to RenderDemo * Add tests * Implement fix * Minor improvements Remove leftover vars/params Replace some `if`s with terniary assignment Improve comments Unduplicate `playbackReversed` code * Add unit test DelayBetweenIterations_Behind_Initial_Point_Is_In_Front_Of_Iterations * Add animation time precision * Add missing check for negative `DelayBetweenIterations` * Fix zero duration regression --------- Co-authored-by: Julien Lebosquain <julien@lebosquain.net>pull/21921/head
committed by
GitHub
6 changed files with 1059 additions and 109 deletions
@ -0,0 +1,117 @@ |
|||
<UserControl |
|||
xmlns="https://github.com/avaloniaui" |
|||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
|||
xmlns:viewModels="using:RenderDemo.ViewModels" |
|||
x:Class="RenderDemo.Pages.AnimationSpeedPage" |
|||
x:DataType="viewModels:AnimationSpeedPageViewModel" |
|||
MaxWidth="600"> |
|||
<UserControl.Styles> |
|||
<Style Selector="TextBlock.rotatorNINF"> |
|||
<Style.Animations> |
|||
<Animation Duration="0:0:1" IterationCount="INFINITE" |
|||
Delay="{Binding Delay, Mode=OneWay}" |
|||
DelayBetweenIterations="{Binding DelayIters, Mode=OneWay}" |
|||
PlaybackDirection="{Binding PlaybackDirection, Mode=OneWay}" |
|||
SpeedRatio="{Binding SpeedRatio, Mode=OneWay}"> |
|||
<KeyFrame Cue="0%"> |
|||
<Setter Property="RotateTransform.Angle" Value="0.0" /> |
|||
</KeyFrame> |
|||
<KeyFrame Cue="100%"> |
|||
<Setter Property="RotateTransform.Angle" Value="360.0" /> |
|||
</KeyFrame> |
|||
</Animation> |
|||
</Style.Animations> |
|||
</Style> |
|||
<Style Selector="TextBlock.rotatorN10"> |
|||
<Style.Animations> |
|||
<Animation Duration="0:0:1" IterationCount="10" |
|||
Delay="{Binding Delay, Mode=OneWay}" |
|||
DelayBetweenIterations="{Binding DelayIters, Mode=OneWay}" |
|||
PlaybackDirection="{Binding PlaybackDirection, Mode=OneWay}" |
|||
SpeedRatio="{Binding SpeedRatio, Mode=OneWay}"> |
|||
<KeyFrame Cue="0%"> |
|||
<Setter Property="RotateTransform.Angle" Value="0.0" /> |
|||
</KeyFrame> |
|||
<KeyFrame Cue="100%"> |
|||
<Setter Property="RotateTransform.Angle" Value="360.0" /> |
|||
</KeyFrame> |
|||
</Animation> |
|||
</Style.Animations> |
|||
</Style> |
|||
<Style Selector="TextBlock.rotatorRINF"> |
|||
<Style.Animations> |
|||
<Animation Duration="0:0:1" IterationCount="INFINITE" |
|||
Delay="{Binding Delay, Mode=OneWay}" |
|||
DelayBetweenIterations="{Binding DelayIters, Mode=OneWay}" |
|||
PlaybackDirection="{Binding PlaybackDirectionOpposite, Mode=OneWay}" |
|||
SpeedRatio="{Binding SpeedRatio, Mode=OneWay}"> |
|||
<KeyFrame Cue="0%"> |
|||
<Setter Property="RotateTransform.Angle" Value="0.0" /> |
|||
</KeyFrame> |
|||
<KeyFrame Cue="100%"> |
|||
<Setter Property="RotateTransform.Angle" Value="360.0" /> |
|||
</KeyFrame> |
|||
</Animation> |
|||
</Style.Animations> |
|||
</Style> |
|||
<Style Selector="TextBlock.rotatorR10"> |
|||
<Style.Animations> |
|||
<Animation Duration="0:0:1" IterationCount="10" |
|||
Delay="{Binding Delay, Mode=OneWay}" |
|||
DelayBetweenIterations="{Binding DelayIters, Mode=OneWay}" |
|||
PlaybackDirection="{Binding PlaybackDirectionOpposite, Mode=OneWay}" |
|||
SpeedRatio="{Binding SpeedRatio, Mode=OneWay}"> |
|||
<KeyFrame Cue="0%"> |
|||
<Setter Property="RotateTransform.Angle" Value="0.0" /> |
|||
</KeyFrame> |
|||
<KeyFrame Cue="100%"> |
|||
<Setter Property="RotateTransform.Angle" Value="360.0" /> |
|||
</KeyFrame> |
|||
</Animation> |
|||
</Style.Animations> |
|||
</Style> |
|||
</UserControl.Styles> |
|||
<ScrollViewer> |
|||
<StackPanel Orientation="Vertical"> |
|||
<Grid RowDefinitions="Auto,Auto,Auto,1*" ColumnDefinitions="Auto,5*,Auto"> |
|||
<TextBlock Grid.Row="0" Grid.Column="0" Text="SpeedRatio:" /> |
|||
<Slider Grid.Row="0" Grid.Column="1" |
|||
Value="{Binding SpeedRatio, Mode=OneWayToSource}" |
|||
Minimum="0" Maximum="2" /> |
|||
|
|||
<TextBlock Grid.Row="1" Grid.Column="0" Text="Delay:" /> |
|||
<Slider Grid.Row="1" Grid.Column="1" |
|||
Value="{Binding DelayInput, Mode=OneWayToSource}" |
|||
Minimum="0" Maximum="10" /> |
|||
|
|||
<TextBlock Grid.Row="2" Grid.Column="0" Text="DelayIters:" /> |
|||
<Slider Grid.Row="2" Grid.Column="1" |
|||
Value="{Binding DelayItersInput, Mode=OneWayToSource}" |
|||
Minimum="0" Maximum="10" /> |
|||
|
|||
<ComboBox Grid.Row="0" Grid.RowSpan="3" Grid.Column="2" |
|||
ItemsSource="{Binding PlaybackDirections}" |
|||
SelectedValue="{Binding PlaybackDirection, Mode=OneWayToSource}" /> |
|||
</Grid> |
|||
<Grid RowDefinitions="Auto,1*,Auto,1*" ColumnDefinitions="Auto,Auto" |
|||
Grid.Row="3" Grid.ColumnSpan="3" Height="400"> |
|||
<TextBlock Grid.Row="0" Grid.Column="0" Text="PlayDir=AsSelected; Iters=INF" /> |
|||
<TextBlock Grid.Row="1" Grid.Column="0" Text="Rotate me" Classes="rotatorNINF" |
|||
HorizontalAlignment="Center" VerticalAlignment="Center" /> |
|||
|
|||
<TextBlock Grid.Row="2" Grid.Column="0" Text="PlayDir=AsSelected; Iters=10" /> |
|||
<TextBlock Grid.Row="3" Grid.Column="0" Text="Rotate me" Classes="rotatorN10" |
|||
HorizontalAlignment="Center" VerticalAlignment="Center" /> |
|||
|
|||
<TextBlock Grid.Row="0" Grid.Column="1" Text="PlayDir=Opposite; Iters=INF" /> |
|||
<TextBlock Grid.Row="1" Grid.Column="1" Text="Rotate me" Classes="rotatorRINF" |
|||
HorizontalAlignment="Center" VerticalAlignment="Center" /> |
|||
|
|||
<TextBlock Grid.Row="2" Grid.Column="1" Text="PlayDir=Opposite; Iters=10" /> |
|||
<TextBlock Grid.Row="3" Grid.Column="1" Text="Rotate me" Classes="rotatorR10" |
|||
HorizontalAlignment="Center" VerticalAlignment="Center" /> |
|||
</Grid> |
|||
|
|||
</StackPanel> |
|||
</ScrollViewer> |
|||
</UserControl> |
|||
@ -0,0 +1,23 @@ |
|||
using System.Reactive.Linq; |
|||
using Avalonia; |
|||
using Avalonia.Animation; |
|||
using Avalonia.Controls; |
|||
using Avalonia.Controls.Shapes; |
|||
using Avalonia.Markup.Xaml; |
|||
using RenderDemo.ViewModels; |
|||
|
|||
namespace RenderDemo.Pages; |
|||
|
|||
public class AnimationSpeedPage : UserControl |
|||
{ |
|||
public AnimationSpeedPage() |
|||
{ |
|||
InitializeComponent(); |
|||
this.DataContext = new AnimationSpeedPageViewModel(); |
|||
} |
|||
|
|||
private void InitializeComponent() |
|||
{ |
|||
AvaloniaXamlLoader.Load(this); |
|||
} |
|||
} |
|||
@ -0,0 +1,103 @@ |
|||
using System; |
|||
using System.Collections; |
|||
using Avalonia.Animation; |
|||
using MiniMvvm; |
|||
|
|||
namespace RenderDemo.ViewModels; |
|||
|
|||
public class AnimationSpeedPageViewModel : ViewModelBase |
|||
{ |
|||
private double _speedRatio; |
|||
public double SpeedRatio |
|||
{ |
|||
get => _speedRatio; |
|||
set => RaiseAndSetIfChanged(ref _speedRatio, value); |
|||
} |
|||
|
|||
private static readonly PlaybackDirection[] s_playbackDirections = [ |
|||
PlaybackDirection.Normal, |
|||
PlaybackDirection.Reverse, |
|||
PlaybackDirection.Alternate, |
|||
PlaybackDirection.AlternateReverse |
|||
]; |
|||
public PlaybackDirection[] PlaybackDirections |
|||
{ |
|||
get => s_playbackDirections; |
|||
} |
|||
|
|||
private PlaybackDirection GetOppositePlaybackDirection(PlaybackDirection value) |
|||
{ |
|||
switch (value) |
|||
{ |
|||
case PlaybackDirection.Normal: |
|||
return PlaybackDirection.Reverse; |
|||
case PlaybackDirection.Reverse: |
|||
return PlaybackDirection.Normal; |
|||
case PlaybackDirection.Alternate: |
|||
return PlaybackDirection.AlternateReverse; |
|||
case PlaybackDirection.AlternateReverse: |
|||
return PlaybackDirection.Alternate; |
|||
} |
|||
throw new ArgumentOutOfRangeException(); |
|||
} |
|||
|
|||
private PlaybackDirection _playbackDirection; |
|||
public PlaybackDirection PlaybackDirection |
|||
{ |
|||
get => _playbackDirection; |
|||
set |
|||
{ |
|||
_playbackDirection = value; |
|||
RaisePropertyChanged(nameof(PlaybackDirection)); |
|||
_playbackDirectionOpposite = GetOppositePlaybackDirection(value); |
|||
RaisePropertyChanged(nameof(PlaybackDirectionOpposite)); |
|||
} |
|||
} |
|||
|
|||
private PlaybackDirection _playbackDirectionOpposite; |
|||
public PlaybackDirection PlaybackDirectionOpposite |
|||
{ |
|||
get => _playbackDirectionOpposite; |
|||
set |
|||
{ |
|||
_playbackDirectionOpposite = value; |
|||
RaisePropertyChanged(nameof(PlaybackDirectionOpposite)); |
|||
_playbackDirection = GetOppositePlaybackDirection(value); |
|||
RaisePropertyChanged(nameof(PlaybackDirection)); |
|||
} |
|||
} |
|||
|
|||
private TimeSpan _delay; |
|||
public TimeSpan Delay |
|||
{ |
|||
get => _delay; |
|||
set => RaiseAndSetIfChanged(ref _delay, value); |
|||
} |
|||
|
|||
public double DelayInput |
|||
{ |
|||
get => _delay.TotalSeconds; |
|||
set => Delay = TimeSpan.FromSeconds(value); |
|||
} |
|||
|
|||
private TimeSpan _delayIters; |
|||
public TimeSpan DelayIters |
|||
{ |
|||
get => _delayIters; |
|||
set => RaiseAndSetIfChanged(ref _delayIters, value); |
|||
} |
|||
|
|||
public double DelayItersInput |
|||
{ |
|||
get => _delayIters.TotalSeconds; |
|||
set => DelayIters = TimeSpan.FromSeconds(value); |
|||
} |
|||
|
|||
public AnimationSpeedPageViewModel() |
|||
{ |
|||
SpeedRatio = 1; |
|||
PlaybackDirection = PlaybackDirection.Normal; |
|||
DelayInput = 0; |
|||
DelayItersInput = 0; |
|||
} |
|||
} |
|||
Loading…
Reference in new issue