1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-31 17:53:32 +00:00

Added timeline scrolling

Added timeline caret
This commit is contained in:
Robert 2020-01-02 19:27:16 +01:00
parent 884bd0f03b
commit 615f5b0b40
6 changed files with 81 additions and 58 deletions

View File

@ -18,13 +18,17 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline.Contr
new FrameworkPropertyMetadata(default(int), FrameworkPropertyMetadataOptions.AffectsRender)); new FrameworkPropertyMetadata(default(int), FrameworkPropertyMetadataOptions.AffectsRender));
public static readonly DependencyProperty FrameStartProperty = DependencyProperty.Register(nameof(FrameStart), typeof(int), typeof(TimelineTime), public static readonly DependencyProperty HorizontalOffsetProperty = DependencyProperty.Register(nameof(HorizontalOffset), typeof(double), typeof(TimelineTime),
new FrameworkPropertyMetadata(default(int), FrameworkPropertyMetadataOptions.AffectsRender)); new FrameworkPropertyMetadata(default(double), FrameworkPropertyMetadataOptions.AffectsRender));
public static readonly DependencyProperty VisibleWidthProperty = DependencyProperty.Register(nameof(VisibleWidth), typeof(double), typeof(TimelineTime),
new FrameworkPropertyMetadata(default(double), FrameworkPropertyMetadataOptions.AffectsRender));
private double _subd1; private double _subd1;
private double _subd2; private double _subd2;
private double _subd3; private double _subd3;
public Brush Fill public Brush Fill
{ {
get => (Brush) GetValue(FillProperty); get => (Brush) GetValue(FillProperty);
@ -43,31 +47,45 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline.Contr
set => SetValue(PixelsPerSecondProperty, value); set => SetValue(PixelsPerSecondProperty, value);
} }
public int FrameStart public double HorizontalOffset
{ {
get => (int) GetValue(FrameStartProperty); get => (double) GetValue(HorizontalOffsetProperty);
set => SetValue(FrameStartProperty, value); set => SetValue(HorizontalOffsetProperty, value);
}
public double VisibleWidth
{
get => (double) GetValue(VisibleWidthProperty);
set => SetValue(VisibleWidthProperty, value);
} }
// TODO: Does this get called when the size changes?
protected override void OnRender(DrawingContext drawingContext) protected override void OnRender(DrawingContext drawingContext)
{ {
SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Aliased);
base.OnRender(drawingContext); base.OnRender(drawingContext);
UpdateTimeScale(); UpdateTimeScale();
var linePen = new Pen(Fill, 1); var linePen = new Pen(Fill, 1);
var width = RenderSize.Width; var width = HorizontalOffset + VisibleWidth;
var frameStart = 0;
var units = PixelsPerSecond / _subd1; var units = PixelsPerSecond / _subd1;
var offsetUnits = FrameStart * PixelsPerSecond % units; var offsetUnits = frameStart * PixelsPerSecond % units;
// Labels // Labels
var count = (width + offsetUnits) / units; var count = (width + offsetUnits) / units;
for (var i = 0; i < count; i++) for (var i = 0; i < count; i++)
{ {
var x = i * units - offsetUnits; var x = i * units - offsetUnits + 1;
var t = TimeSpan.FromSeconds((i * units - offsetUnits) / PixelsPerSecond + FrameStart); // Add a 100px margin to allow the text to partially render when needed
if (PixelsPerSecond > 200) if (x < HorizontalOffset - 100 || x > HorizontalOffset + width)
continue;
var t = TimeSpan.FromSeconds((i * units - offsetUnits) / PixelsPerSecond + frameStart);
// 0.00 is always formatted as 0.00
if (t == TimeSpan.Zero)
RenderLabel(drawingContext, "0.00", x);
else if (PixelsPerSecond > 200)
RenderLabel(drawingContext, $"{Math.Floor(t.TotalSeconds):00}.{t.Milliseconds:000}", x); RenderLabel(drawingContext, $"{Math.Floor(t.TotalSeconds):00}.{t.Milliseconds:000}", x);
else if (PixelsPerSecond > 60) else if (PixelsPerSecond > 60)
RenderLabel(drawingContext, $"{Math.Floor(t.TotalSeconds):00}.{t.Milliseconds:000}", x); RenderLabel(drawingContext, $"{Math.Floor(t.TotalSeconds):00}.{t.Milliseconds:000}", x);
@ -80,8 +98,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline.Contr
count = (width + offsetUnits) / units; count = (width + offsetUnits) / units;
for (var i = 0; i < count; i++) for (var i = 0; i < count; i++)
{ {
var x = i * units - offsetUnits; var x = i * units - offsetUnits + 1;
drawingContext.DrawLine(linePen, new Point(x, 15), new Point(x, 30)); if (x > HorizontalOffset && x < HorizontalOffset + width)
drawingContext.DrawLine(linePen, new Point(x, 20), new Point(x, 30));
} }
// Small ticks // Small ticks
@ -91,8 +110,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline.Contr
for (var i = 0; i < count; i++) for (var i = 0; i < count; i++)
{ {
if (Math.Abs(i % mul) < 0.001) continue; if (Math.Abs(i % mul) < 0.001) continue;
var x = i * units - offsetUnits; var x = i * units - offsetUnits + 1;
drawingContext.DrawLine(linePen, new Point(x, 22), new Point(x, 30)); if (x > HorizontalOffset && x < HorizontalOffset + width)
drawingContext.DrawLine(linePen, new Point(x, 25), new Point(x, 30));
} }
} }
@ -100,7 +120,11 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline.Contr
{ {
var typeFace = new Typeface(FontFamily, new FontStyle(), new FontWeight(), new FontStretch()); var typeFace = new Typeface(FontFamily, new FontStyle(), new FontWeight(), new FontStretch());
var formattedText = new FormattedText(text, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, typeFace, 9, Fill, null, VisualTreeHelper.GetDpi(this).PixelsPerDip); var formattedText = new FormattedText(text, CultureInfo.CurrentUICulture, FlowDirection.LeftToRight, typeFace, 9, Fill, null, VisualTreeHelper.GetDpi(this).PixelsPerDip);
drawingContext.DrawText(formattedText, new Point(x, 0)); if (x == 1)
drawingContext.DrawText(formattedText, new Point(x, 2));
else
drawingContext.DrawText(formattedText, new Point(x - formattedText.Width /2, 2));
} }
private void UpdateTimeScale() private void UpdateTimeScale()

View File

@ -9,36 +9,6 @@
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance timeline:LayerPropertiesTimelineViewModel}"> d:DataContext="{d:DesignInstance timeline:LayerPropertiesTimelineViewModel}">
<UserControl.Resources>
<Style x:Key="ItemsControlVirtualizedStyle" TargetType="ItemsControl">
<Setter Property="VirtualizingStackPanel.IsVirtualizing" Value="True" />
<Setter Property="ScrollViewer.CanContentScroll" Value="True" />
<Setter Property="ItemsPanel">
<Setter.Value>
<ItemsPanelTemplate>
<VirtualizingStackPanel />
</ItemsPanelTemplate>
</Setter.Value>
</Setter>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ItemsControl">
<Border
BorderThickness="{TemplateBinding Border.BorderThickness}"
Padding="{TemplateBinding Control.Padding}"
BorderBrush="{TemplateBinding Border.BorderBrush}"
Background="{TemplateBinding Panel.Background}"
SnapsToDevicePixels="True">
<ScrollViewer Padding="{TemplateBinding Control.Padding}" Focusable="False">
<ItemsPresenter SnapsToDevicePixels="{TemplateBinding UIElement.SnapsToDevicePixels}" />
</ScrollViewer>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid> <Grid>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="*" /> <RowDefinition Height="*" />
@ -48,15 +18,24 @@
<ScrollViewer x:Name="Keyframes" <ScrollViewer x:Name="Keyframes"
Grid.Row="0" Grid.Row="0"
HorizontalScrollBarVisibility="Visible" HorizontalScrollBarVisibility="Visible"
VerticalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden">
Padding="5 0 5 0"> <StackPanel x:Name="KeyframesContainer">
<StackPanel> <!-- Time caret -->
<controls:TimelineTime Height="30" Fill="{StaticResource MaterialDesignBody}" PixelsPerSecond="{Binding PixelsPerSecond}"/> <Canvas ZIndex="10" Height="25" Margin="{Binding TimeCaretPosition}">
<Polygon Points="-10,0 0,20, 10,00" Fill="{StaticResource SecondaryAccentBrush}" />
<Line X1="0" X2="0" Y1="0" Y2="10000" StrokeThickness="2" Stroke="{StaticResource SecondaryAccentBrush}" />
</Canvas>
<!-- Time -->
<controls:TimelineTime Height="30"
Fill="{DynamicResource MaterialDesignBody}"
PixelsPerSecond="{Binding PixelsPerSecond}"
HorizontalOffset="{Binding ContentHorizontalOffset, ElementName=Keyframes}"
VisibleWidth="{Binding ActualWidth, ElementName=Keyframes}" />
<!-- Keyframes -->
<ItemsControl ItemsSource="{Binding TimelinePropertyRailViewModels}"> <ItemsControl ItemsSource="{Binding TimelinePropertyRailViewModels}">
<ItemsControl.ItemTemplate> <ItemsControl.ItemTemplate>
<DataTemplate> <DataTemplate>
<ContentControl s:View.Model="{Binding}" /> <ContentControl s:View.Model="{Binding}" HorizontalAlignment="Stretch" />
</DataTemplate> </DataTemplate>
</ItemsControl.ItemTemplate> </ItemsControl.ItemTemplate>
</ItemsControl> </ItemsControl>

View File

@ -1,4 +1,7 @@
using System.Collections.Generic; using System;
using System.Collections.Generic;
using System.Windows;
using System.Windows.Markup;
using Stylet; using Stylet;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
@ -11,6 +14,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
{ {
TimelinePropertyRailViewModels = new BindableCollection<TimelinePropertyRailViewModel>(); TimelinePropertyRailViewModels = new BindableCollection<TimelinePropertyRailViewModel>();
TimeCaretTime = TimeSpan.FromSeconds(3);
CreateTestValues(); CreateTestValues();
Update(); Update();
} }
@ -25,6 +29,13 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
} }
} }
public TimeSpan TimeCaretTime { get; set; }
public Thickness TimeCaretPosition
{
get => new Thickness(TimeCaretTime.TotalSeconds * PixelsPerSecond, 0, 0, 0);
set => TimeCaretTime = TimeSpan.FromSeconds(value.Left / PixelsPerSecond);
}
public BindableCollection<TimelinePropertyRailViewModel> TimelinePropertyRailViewModels { get; set; } public BindableCollection<TimelinePropertyRailViewModel> TimelinePropertyRailViewModels { get; set; }
private void CreateTestValues() private void CreateTestValues()

View File

@ -9,8 +9,12 @@
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance local:TimelinePropertyRailViewModel}"> d:DataContext="{d:DesignInstance local:TimelinePropertyRailViewModel}">
<Border BorderThickness="0,1" BorderBrush="{StaticResource MaterialDesignTextAreaBorder}" Height="25" Margin="0,0,0,-1"> <Border BorderThickness="0,1" BorderBrush="{DynamicResource MaterialDesignDivider}" Height="25" Margin="0,0,0,-1">
<ItemsControl ItemsSource="{Binding TimelineKeyframeViewModels}"> <ItemsControl ItemsSource="{Binding TimelineKeyframeViewModels}"
Width="{Binding Width}"
MinWidth="{Binding ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ScrollViewer}}"
Background="{DynamicResource MaterialDesignToolBarBackground}"
HorizontalAlignment="Left">
<ItemsControl.ItemsPanel> <ItemsControl.ItemsPanel>
<ItemsPanelTemplate> <ItemsPanelTemplate>
<Canvas /> <Canvas />

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using Stylet; using Stylet;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
@ -13,6 +14,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
} }
public BindableCollection<TimelineKeyframeViewModel> TimelineKeyframeViewModels { get; set; } public BindableCollection<TimelineKeyframeViewModel> TimelineKeyframeViewModels { get; set; }
public double Width { get; set; }
public void CreateTestValues() public void CreateTestValues()
{ {
@ -31,8 +33,11 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
foreach (var timelineKeyframeViewModel in TimelineKeyframeViewModels) foreach (var timelineKeyframeViewModel in TimelineKeyframeViewModels)
timelineKeyframeViewModel.Update(pixelsPerSecond); timelineKeyframeViewModel.Update(pixelsPerSecond);
if (pixelsPerSecond == 10) // End time is the last keyframe + 10 sec
Console.WriteLine(); var lastKeyFrame = TimelineKeyframeViewModels.OrderByDescending(t => t.Position).FirstOrDefault();
var endTime = lastKeyFrame?.Position.Add(new TimeSpan(0, 0, 0, 10)) ?? TimeSpan.FromSeconds(10);
Width = endTime.TotalSeconds * pixelsPerSecond;
} }
} }
} }