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:
parent
884bd0f03b
commit
615f5b0b40
@ -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()
|
||||||
|
|||||||
@ -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>
|
||||||
|
|||||||
@ -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()
|
||||||
|
|||||||
@ -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 />
|
||||||
|
|||||||
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user