From 615f5b0b40a91317c6cf45f6aff8ad4a29800393 Mon Sep 17 00:00:00 2001 From: Robert Date: Thu, 2 Jan 2020 19:27:16 +0100 Subject: [PATCH] Added timeline scrolling Added timeline caret --- .../Timeline/Controls/TimelineTime.cs | 56 +++++++++++++------ .../Timeline/LayerPropertiesTimelineView.xaml | 51 +++++------------ .../LayerPropertiesTimelineViewModel.cs | 13 ++++- .../Timeline/TimelinePropertyRailView.xaml | 8 ++- .../Timeline/TimelinePropertyRailViewModel.cs | 9 ++- .../Screens/Settings/SettingsViewModel.cs | 2 +- 6 files changed, 81 insertions(+), 58 deletions(-) diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/Controls/TimelineTime.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/Controls/TimelineTime.cs index 37b6a5838..78554e8a2 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/Controls/TimelineTime.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/Controls/TimelineTime.cs @@ -18,13 +18,17 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline.Contr new FrameworkPropertyMetadata(default(int), FrameworkPropertyMetadataOptions.AffectsRender)); - public static readonly DependencyProperty FrameStartProperty = DependencyProperty.Register(nameof(FrameStart), typeof(int), typeof(TimelineTime), - new FrameworkPropertyMetadata(default(int), FrameworkPropertyMetadataOptions.AffectsRender)); + public static readonly DependencyProperty HorizontalOffsetProperty = DependencyProperty.Register(nameof(HorizontalOffset), typeof(double), typeof(TimelineTime), + 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 _subd2; private double _subd3; + public Brush Fill { get => (Brush) GetValue(FillProperty); @@ -43,31 +47,45 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline.Contr set => SetValue(PixelsPerSecondProperty, value); } - public int FrameStart + public double HorizontalOffset { - get => (int) GetValue(FrameStartProperty); - set => SetValue(FrameStartProperty, value); + get => (double) GetValue(HorizontalOffsetProperty); + 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) { + SetValue(RenderOptions.EdgeModeProperty, EdgeMode.Aliased); base.OnRender(drawingContext); UpdateTimeScale(); var linePen = new Pen(Fill, 1); - var width = RenderSize.Width; + var width = HorizontalOffset + VisibleWidth; + var frameStart = 0; var units = PixelsPerSecond / _subd1; - var offsetUnits = FrameStart * PixelsPerSecond % units; + var offsetUnits = frameStart * PixelsPerSecond % units; // Labels var count = (width + offsetUnits) / units; for (var i = 0; i < count; i++) { - var x = i * units - offsetUnits; - var t = TimeSpan.FromSeconds((i * units - offsetUnits) / PixelsPerSecond + FrameStart); - if (PixelsPerSecond > 200) + var x = i * units - offsetUnits + 1; + // Add a 100px margin to allow the text to partially render when needed + 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); else if (PixelsPerSecond > 60) 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; for (var i = 0; i < count; i++) { - var x = i * units - offsetUnits; - drawingContext.DrawLine(linePen, new Point(x, 15), new Point(x, 30)); + var x = i * units - offsetUnits + 1; + if (x > HorizontalOffset && x < HorizontalOffset + width) + drawingContext.DrawLine(linePen, new Point(x, 20), new Point(x, 30)); } // Small ticks @@ -91,8 +110,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline.Contr for (var i = 0; i < count; i++) { if (Math.Abs(i % mul) < 0.001) continue; - var x = i * units - offsetUnits; - drawingContext.DrawLine(linePen, new Point(x, 22), new Point(x, 30)); + var x = i * units - offsetUnits + 1; + 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 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() diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/LayerPropertiesTimelineView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/LayerPropertiesTimelineView.xaml index 9a3d4cfe7..59c165490 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/LayerPropertiesTimelineView.xaml +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/LayerPropertiesTimelineView.xaml @@ -9,36 +9,6 @@ mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800" d:DataContext="{d:DesignInstance timeline:LayerPropertiesTimelineViewModel}"> - - - - @@ -48,15 +18,24 @@ - - - + VerticalScrollBarVisibility="Hidden"> + + + + + + + + + - + diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/LayerPropertiesTimelineViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/LayerPropertiesTimelineViewModel.cs index b175c1fed..ed271a0ef 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/LayerPropertiesTimelineViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/LayerPropertiesTimelineViewModel.cs @@ -1,4 +1,7 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; +using System.Windows; +using System.Windows.Markup; using Stylet; namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline @@ -11,6 +14,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline { TimelinePropertyRailViewModels = new BindableCollection(); + TimeCaretTime = TimeSpan.FromSeconds(3); CreateTestValues(); 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 TimelinePropertyRailViewModels { get; set; } private void CreateTestValues() diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelinePropertyRailView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelinePropertyRailView.xaml index 56024a389..17dab3685 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelinePropertyRailView.xaml +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelinePropertyRailView.xaml @@ -9,8 +9,12 @@ mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800" d:DataContext="{d:DesignInstance local:TimelinePropertyRailViewModel}"> - - + + diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelinePropertyRailViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelinePropertyRailViewModel.cs index 9d9615180..0ec42d02b 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelinePropertyRailViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Timeline/TimelinePropertyRailViewModel.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using Stylet; namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline @@ -13,6 +14,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline } public BindableCollection TimelineKeyframeViewModels { get; set; } + public double Width { get; set; } public void CreateTestValues() { @@ -31,8 +33,11 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline foreach (var timelineKeyframeViewModel in TimelineKeyframeViewModels) timelineKeyframeViewModel.Update(pixelsPerSecond); - if (pixelsPerSecond == 10) - Console.WriteLine(); + // End time is the last keyframe + 10 sec + 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; } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs b/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs index 263cdc7de..1ac600de7 100644 --- a/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs +++ b/src/Artemis.UI/Screens/Settings/SettingsViewModel.cs @@ -126,7 +126,7 @@ namespace Artemis.UI.Screens.Settings { _windowManager.ShowWindow(_kernel.Get()); } - + public void ShowLogsFolder() { Process.Start(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Logs"));