OverviewFilesCommitsIssuesDocsReleasesPeers

ifsrenderer-linux / WpfDisplay / Views / Animation / AnimationPanel.xaml

250 lines · xaml ref:
<UserControl x:Class="WpfDisplay.Views.Animation.AnimationPanel"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
             xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
             xmlns:sys="clr-namespace:System;assembly=mscorlib"
             xmlns:local="clr-namespace:WpfDisplay.Views.Animation"
             xmlns:common="clr-namespace:WpfDisplay.Views"
             xmlns:viewModels="clr-namespace:WpfDisplay.ViewModels"
             xmlns:conv="clr-namespace:WpfDisplay.Converters"
             xmlns:md="http://materialdesigninxaml.net/winfx/xaml/themes"
             mc:Ignorable="d" x:Name="animationPanel"
             d:DataContext="{d:DesignInstance Type=viewModels:AnimationViewModel, IsDesignTimeCreatable=False}"
             d:DesignHeight="300" d:DesignWidth="800">
    <UserControl.Resources>
        <DrawingBrush x:Key="linesBrush" TileMode="Tile"
                    Viewport="0,0,50,1" ViewportUnits="Absolute"
                    Viewbox="0,0,50,1" ViewboxUnits="Absolute">
            <DrawingBrush.Drawing>
                <GeometryDrawing>
                    <GeometryDrawing.Pen>
                        <Pen Brush="DarkGray" Thickness="2"/>
                    </GeometryDrawing.Pen>
                    <GeometryDrawing.Geometry>
                        <GeometryGroup>
                            <LineGeometry StartPoint="0,0" EndPoint="0,1"></LineGeometry>
                        </GeometryGroup>
                    </GeometryDrawing.Geometry>
                </GeometryDrawing>
            </DrawingBrush.Drawing>
        </DrawingBrush>
        <Style x:Key="timelineButtonStyle" TargetType="{x:Type Button}" BasedOn="{StaticResource MaterialDesignOutlinedLightButton}">
            <Setter Property="Visibility" Value="Hidden" />
            <Setter Property="Height" Value="15"/>
            <Setter Property="Padding" Value="0"/>
            <Setter Property="Margin" Value="5 0"/>
            <Setter Property="BorderThickness" Value="0"/>
            <Setter Property="FontSize" Value="8"/>
            <Style.Triggers>
                <DataTrigger Binding="{Binding IsMouseOver, 
                    RelativeSource={RelativeSource Mode=TemplatedParent}}" Value="True">
                    <Setter Property="Visibility" Value="Visible" />
                </DataTrigger>
            </Style.Triggers>
        </Style>
    </UserControl.Resources>
    <Grid>
        <Grid.ColumnDefinitions>
            <ColumnDefinition Width="200"/>
            <ColumnDefinition Width="2"/>
            <ColumnDefinition Width="*"/>
        </Grid.ColumnDefinitions>
        <Grid.RowDefinitions>
            <RowDefinition Height="60"/>
            <RowDefinition Height="30"/>
            <RowDefinition Height="*"/>
        </Grid.RowDefinitions>
        <Grid Grid.Column="0" Grid.Row="0" Margin="4">
            <Button Command="{Binding JumpToStartCommand}" ToolTip="Stop animation"
                    IsEnabled="{Binding IsExportingFrames, Converter={StaticResource invertBooleanConverter}}"
                    HorizontalAlignment="Left">
                ⬜
            </Button>
            <ToggleButton Command="{Binding PlayPauseCommand}" ToolTip="Play/Pause animation preview"
                          IsEnabled="{Binding IsExportingFrames, Converter={StaticResource invertBooleanConverter}}"
                          Style="{StaticResource MaterialDesignActionToggleButton}"
                          HorizontalAlignment="Center">
                <Label FontFamily="Monospace" Padding="2,2,0,0" Foreground="Black">▷</Label>
                <md:ToggleButtonAssist.OnContent>
                    <Label FontFamily="Monospace" Padding="0,2,0,0" Foreground="Black">❚❚</Label>
                </md:ToggleButtonAssist.OnContent>
            </ToggleButton>
        </Grid>
        <Grid Grid.Column="0" Grid.Row="1" Margin="4,0">
            <Button Command="{Binding LoadAudioCommand}" HorizontalAlignment="Left" Padding="5" ToolTip="{Binding AudioClipTitle, TargetNullValue=Load audio clip}">
                <TextBlock TextTrimming="CharacterEllipsis">
                🎵 <Run Text="{Binding AudioClipTitle, TargetNullValue=...}"/>
                </TextBlock>
            </Button>
        </Grid>
        <Grid Grid.Column="1" Grid.Row="0" Grid.RowSpan="3" Background="Black"/>
        <Grid Grid.Column="2" Grid.Row="0">
            <common:ValueSlider Value="{Binding ClipFps}" SliderSettings="{Binding FpsSlider}" HorizontalAlignment="Left" MinWidth="100"/>
            <common:ValueSlider Value="{Binding CurrentTimeSeconds}" SliderSettings="{Binding CurrentTimeSlider}"
                                MaxValue="{Binding ClipLength}"
                                Increment="{Binding CurrentTimeIncrement}"
                                HorizontalAlignment="Center" MinWidth="125"/>
            <common:ValueSlider Value="{Binding ClipLength}" SliderSettings="{Binding LengthSlider}" HorizontalAlignment="Right" MinWidth="100"/>
        </Grid>
        <ScrollViewer x:Name="channelHeaderScroller" Grid.Column="0" Grid.Row="2" 
                        VerticalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Hidden"
                        ScrollChanged="ChannelHeaderScroller_ScrollChanged">
            <StackPanel>
                <ItemsControl ItemsSource="{Binding Channels}" AlternationCount="2" Grid.Column="0">
                    <ItemsControl.ItemTemplate>
                        <DataTemplate>
                            <Grid x:Name="alternatingBackgroundGrid1">
                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*"/>
                                    <ColumnDefinition Width="auto"/>
                                </Grid.ColumnDefinitions>
                                <TextBlock Grid.Column="0">
                                    <Hyperlink Command="{Binding DataContext.EditChannelCommand, ElementName=animationPanel}" CommandParameter="{Binding}" 
                                                TextDecorations="None" Foreground="White">
                                        <Run Text="{Binding Name, Mode=OneWay}" />
                                    </Hyperlink>
                                </TextBlock>
                                <Button Grid.Column="2" Style="{StaticResource timelineButtonStyle}"
                                                Command="{Binding DataContext.RemoveChannelCommand, ElementName=animationPanel}" 
                                                CommandParameter="{Binding}">
                                    ❌
                                </Button>
                            </Grid>
                            <DataTemplate.Triggers>
                                <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                                    <Setter TargetName="alternatingBackgroundGrid1" Property="Background" Value="Transparent"/>
                                </Trigger>
                                <Trigger Property="ItemsControl.AlternationIndex" Value="1">
                                    <Setter TargetName="alternatingBackgroundGrid1" Property="Background" Value="#333333"/>
                                </Trigger>
                            </DataTemplate.Triggers>
                        </DataTemplate>
                    </ItemsControl.ItemTemplate>
                </ItemsControl>
                <Button
                    Command="{Binding ImportChannelsCommand}"
                    ToolTip="Import channels from a CSV file where columns are the channel IDs and rows are the frames. Make sure to adjust the Framerate slider to match the CSV data."
                    HorizontalAlignment="Center" Margin="8" Style="{StaticResource MaterialDesignFlatButton}">+ Import...</Button>
            </StackPanel>
        </ScrollViewer>
        <ScrollViewer Grid.Column="2" Grid.Row="1" Grid.RowSpan="2" VerticalScrollBarVisibility="Disabled" HorizontalScrollBarVisibility="Visible">
            <Grid Width="{Binding SheetWidth}" HorizontalAlignment="Left">
                <Grid.RowDefinitions>
                    <RowDefinition Height="30"/>
                    <RowDefinition Height="*"/>
                </Grid.RowDefinitions>
                <Grid Grid.Row="0" Background="#333333" Cursor="SizeWE"
                      MouseMove="TimeScrubber_MouseMove" 
                      MouseDown="TimeScrubber_MouseMove"
                      MouseWheel="TimeScrubber_MouseWheel">
                    <!--Time scrubber-->
                    <Grid IsHitTestVisible="False">
                        <Grid Background="#111111"/>
                        <Grid>
                            <Grid.Background>
                                <ImageBrush x:Name="scrubberAudioBarsImageBrush" Stretch="None" AlignmentX="Left" AlignmentY="Top"/>
                            </Grid.Background>
                        </Grid>
                        <Grid x:Name="scrubberTicksGrid" Background="{StaticResource linesBrush}"/>
                    </Grid>
                </Grid>
                <ScrollViewer x:Name="sheetScroller" Grid.Row="1" VerticalScrollBarVisibility="Hidden" HorizontalScrollBarVisibility="Hidden">
                    <ItemsControl ItemsSource="{Binding Channels}" AlternationCount="2">
                        <ItemsControl.ItemsPanel>
                            <ItemsPanelTemplate>
                                <StackPanel MouseDown="Dopesheet_MouseDown" Background="Transparent"/>
                            </ItemsPanelTemplate>
                        </ItemsControl.ItemsPanel>
                        <ItemsControl.ItemTemplate>
                            <DataTemplate>
                                <Grid x:Name="alternatingBackgroundGrid2" 
                                      Width="{Binding DataContext.SheetWidth, ElementName=animationPanel}"
                                      MouseUp="Channel_MouseUp" MouseDown="Dopesheet_MouseDown">
                                    <Grid.ContextMenu>
                                        <ContextMenu>
                                            <MenuItem Icon="{md:PackIcon Kind=Plus}" Header="_Insert keyframe here" Command="{Binding InsertKeyframeCommand}"/>
                                            <MenuItem Icon="{md:PackIcon Kind=Trash}" Header="_Remove channel" Command="{Binding Source={x:Reference Name=animationPanel}, Path=DataContext.RemoveChannelCommand}" CommandParameter="{Binding}" Foreground="OrangeRed"/>
                                        </ContextMenu>
                                    </Grid.ContextMenu>
                                    <Border BorderThickness="0,0,0,0.5" BorderBrush="Black">
                                        <ItemsControl ItemsSource="{Binding Keyframes}">
                                            <ItemsControl.ItemsPanel>
                                                <ItemsPanelTemplate>
                                                    <Canvas Height="15" ClipToBounds="True"/>
                                                </ItemsPanelTemplate>
                                            </ItemsControl.ItemsPanel>
                                            <ItemsControl.ItemTemplate>
                                                <DataTemplate>
                                                    <local:DopeButton
                                                            Command="{Binding DataContext.JumpToKeyframeCommand, ElementName=animationPanel}" CommandParameter="{Binding}"
                                                            PreviewMouseDown="DopeButton_MouseDown" PreviewMouseMove="DopeButton_MouseMove" PreviewMouseUp="DopeButton_MouseUp"/>
                                                </DataTemplate>
                                            </ItemsControl.ItemTemplate>
                                            <ItemsControl.ItemContainerStyle>
                                                <Style>
                                                    <Setter Property="Canvas.Left" Value="{Binding TimelinePositon}"/>
                                                </Style>
                                            </ItemsControl.ItemContainerStyle>
                                        </ItemsControl>
                                    </Border>
                                </Grid>
                                <DataTemplate.Triggers>
                                    <Trigger Property="ItemsControl.AlternationIndex" Value="0">
                                        <Setter TargetName="alternatingBackgroundGrid2" Property="Background" Value="Transparent"/>
                                    </Trigger>
                                    <Trigger Property="ItemsControl.AlternationIndex" Value="1">
                                        <Setter TargetName="alternatingBackgroundGrid2" Property="Background" Value="#333333"/>
                                    </Trigger>
                                </DataTemplate.Triggers>
                            </DataTemplate>
                        </ItemsControl.ItemTemplate>
                    </ItemsControl>
                </ScrollViewer>
                <Grid Grid.Row="1"
                      Visibility="{Binding EditedChannel, Converter={StaticResource nullVisibilityConverter}}"
                      Background="#333333">
                    <local:CurveEditor DataContext="{Binding EditedChannel}"/>
                </Grid>
                <Line IsHitTestVisible="False" Grid.RowSpan="2"
                    X1="{Binding CurrentTimeScrollPosition}" Y1="0"
                    X2="{Binding CurrentTimeScrollPosition}" Y2="500"
                    Stroke="#88000000"
                    StrokeThickness="3"/>
                <Line IsHitTestVisible="False" Grid.RowSpan="2"
                    X1="{Binding CurrentTimeScrollPosition}" Y1="0"
                    X2="{Binding CurrentTimeScrollPosition}" Y2="500"
                    Stroke="White"
                    StrokeThickness="1"/>
                <Line IsHitTestVisible="False"
                    X1="{Binding CurrentTimeScrollPosition}" Y1="0"
                    X2="{Binding CurrentTimeScrollPosition}" Y2="10"
                    Stroke="White"
                    StrokeThickness="5"/>
            </Grid>
        </ScrollViewer>
        <!--Show guide text when animation sheet is empty-->
        <Grid Grid.Row="2" Grid.Column="2" HorizontalAlignment="Center" VerticalAlignment="Center">
            <Label Visibility="{Binding Channels.Count, Converter={StaticResource equalityToVisibilityConverter}, ConverterParameter={StaticResource zero}}"
                   Foreground="#aaaaaa" FontSize="16">
                🛈 Insert a keyframe by clicking ◇ next to the value!
            </Label>
            <StackPanel Visibility="{Binding IsExportingFrames, Converter={StaticResource betterBooleanToVisibilityConverter}}">
                <ProgressBar Style="{StaticResource MaterialDesignCircularProgressBar}" IsIndeterminate="True" Foreground="Red"/>
                <TextBlock TextAlignment="Center" Foreground="#aaaaaa" FontSize="16" Margin="0,0,0,16">
                    Exporting animation frames...
                </TextBlock>
                <Button Command="{Binding StopExportingFramesCommand}"
                    HorizontalAlignment="Center" Style="{StaticResource MaterialDesignFlatButton}">
                    Cancel
                </Button>
            </StackPanel>
        </Grid>
        <Grid Grid.Column="0" Grid.Row="2" 
              Visibility="{Binding EditedChannel, Converter={StaticResource nullVisibilityConverter}}"
              Background="#333333" d:Visibility="Hidden">
            <local:ChannelEditor DataContext="{Binding EditedChannel}" Padding="4"/>
        </Grid>
    </Grid>
</UserControl>