mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-12 11:56:30 +00:00
Profile editor - Reimplementing the timeline
This commit is contained in:
1 parent
3389bc0109
commit
56ba44dbce
20 files changed
+231
-348
No files matched your search
-34
@@ -1,34 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
||||
{
|
||||
public class LayerPropertyTimelineViewModel<T> : Screen, ILayerPropertyTimelineViewModel
|
||||
{
|
||||
public LayerProperty<T> LayerProperty { get; }
|
||||
public LayerPropertyViewModel LayerPropertyViewModel { get; }
|
||||
|
||||
public LayerPropertyTimelineViewModel(LayerProperty<T> layerProperty, LayerPropertyViewModel layerPropertyViewModel)
|
||||
{
|
||||
LayerProperty = layerProperty;
|
||||
LayerPropertyViewModel = layerPropertyViewModel;
|
||||
}
|
||||
|
||||
public List<TimeSpan> GetAllKeyframePositions()
|
||||
{
|
||||
return LayerProperty.Keyframes.Select(k => k.Position).ToList();
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
public interface ILayerPropertyTimelineViewModel : IScreen, IDisposable
|
||||
{
|
||||
List<TimeSpan> GetAllKeyframePositions();
|
||||
}
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
using Artemis.Core;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline.Rails
|
||||
{
|
||||
public class TimelineGroupViewModel
|
||||
{
|
||||
public LayerPropertyGroup LayerPropertyGroup { get; }
|
||||
|
||||
public TimelineGroupViewModel(LayerPropertyGroup layerPropertyGroup)
|
||||
{
|
||||
LayerPropertyGroup = layerPropertyGroup;
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-11
@@ -1,4 +1,5 @@
|
||||
using System.Windows;
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using Artemis.Core;
|
||||
using Humanizer;
|
||||
@@ -7,17 +8,11 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
{
|
||||
public class TimelineEasingViewModel
|
||||
{
|
||||
private readonly TimelineKeyframeViewModel _keyframeViewModel;
|
||||
private bool _isEasingModeSelected;
|
||||
|
||||
public TimelineEasingViewModel(TimelineKeyframeViewModel keyframeViewModel, Easings.Functions easingFunction)
|
||||
public TimelineEasingViewModel(Easings.Functions easingFunction, bool isSelected)
|
||||
{
|
||||
// Can be null if used by DataBindingViewModel because I'm lazy
|
||||
if (keyframeViewModel != null)
|
||||
{
|
||||
_keyframeViewModel = keyframeViewModel;
|
||||
_isEasingModeSelected = keyframeViewModel.BaseLayerPropertyKeyframe.EasingFunction == easingFunction;
|
||||
}
|
||||
_isEasingModeSelected = isSelected;
|
||||
|
||||
EasingFunction = easingFunction;
|
||||
Description = easingFunction.Humanize();
|
||||
@@ -41,9 +36,15 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
set
|
||||
{
|
||||
_isEasingModeSelected = value;
|
||||
if (_isEasingModeSelected)
|
||||
_keyframeViewModel.SelectEasingMode(this);
|
||||
if (value) OnEasingModeSelected();
|
||||
}
|
||||
}
|
||||
|
||||
public event EventHandler EasingModeSelected;
|
||||
|
||||
protected virtual void OnEasingModeSelected()
|
||||
{
|
||||
EasingModeSelected?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
-13
@@ -1,14 +1,14 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline.TimelinePropertyGroupView"
|
||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline.TimelineGroupView"
|
||||
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:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:layerProperties1="clr-namespace:Artemis.UI.Screens.ProfileEditor.LayerProperties"
|
||||
mc:Ignorable="d"
|
||||
xmlns:layerProperties="clr-namespace:Artemis.UI.Screens.ProfileEditor.LayerProperties"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:TimelinePropertyGroupViewModel}"
|
||||
d:DataContext="{d:DesignInstance local:TimelineGroupViewModel}"
|
||||
Visibility="{Binding LayerPropertyGroupViewModel.IsVisible, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
@@ -20,7 +20,7 @@
|
||||
<ItemsControl Grid.Row="0"
|
||||
Height="24"
|
||||
Visibility="{Binding LayerPropertyGroupViewModel.IsExpanded, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}"
|
||||
ItemsSource="{Binding TimelineKeyframeViewModels}"
|
||||
ItemsSource="{Binding KeyframePositions}"
|
||||
Background="{DynamicResource MaterialDesignToolBarBackground}"
|
||||
HorizontalAlignment="Stretch">
|
||||
<ItemsControl.ItemsPanel>
|
||||
@@ -59,14 +59,13 @@
|
||||
</Style>
|
||||
</ItemsControl.ItemContainerStyle>
|
||||
<ItemsControl.Resources>
|
||||
<DataTemplate DataType="{x:Type layerProperties1:LayerPropertyGroupViewModel}">
|
||||
<ContentControl s:View.Model="{Binding TimelinePropertyGroupViewModel}" IsTabStop="False" HorizontalAlignment="Stretch" />
|
||||
<DataTemplate DataType="{x:Type layerProperties:LayerPropertyGroupViewModel}">
|
||||
<ContentControl s:View.Model="{Binding TimelineGroupViewModel}" IsTabStop="False" HorizontalAlignment="Stretch" />
|
||||
</DataTemplate>
|
||||
<DataTemplate DataType="{x:Type layerProperties1:LayerPropertyViewModel}">
|
||||
<ContentControl s:View.Model="{Binding TimelinePropertyBaseViewModel}" IsTabStop="False" HorizontalAlignment="Stretch" />
|
||||
<DataTemplate DataType="{x:Type layerProperties:LayerPropertyViewModel}">
|
||||
<ContentControl s:View.Model="{Binding TimelinePropertyViewModel}" IsTabStop="False" HorizontalAlignment="Stretch" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.Resources>
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
</UserControl>
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
{
|
||||
public class TimelineGroupViewModel : IDisposable
|
||||
{
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
|
||||
public TimelineGroupViewModel(LayerPropertyGroupViewModel layerPropertyGroupViewModel, IProfileEditorService profileEditorService)
|
||||
{
|
||||
_profileEditorService = profileEditorService;
|
||||
|
||||
LayerPropertyGroupViewModel = layerPropertyGroupViewModel;
|
||||
LayerPropertyGroup = LayerPropertyGroupViewModel.LayerPropertyGroup;
|
||||
KeyframePositions = new BindableCollection<double>();
|
||||
|
||||
_profileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||
UpdateKeyframePositions();
|
||||
}
|
||||
|
||||
public LayerPropertyGroupViewModel LayerPropertyGroupViewModel { get; }
|
||||
public LayerPropertyGroup LayerPropertyGroup { get; }
|
||||
|
||||
public BindableCollection<double> KeyframePositions { get; }
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_profileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||
}
|
||||
|
||||
private void ProfileEditorServiceOnPixelsPerSecondChanged(object? sender, EventArgs e)
|
||||
{
|
||||
UpdateKeyframePositions();
|
||||
}
|
||||
|
||||
public void UpdateKeyframePositions()
|
||||
{
|
||||
KeyframePositions.Clear();
|
||||
KeyframePositions.AddRange(LayerPropertyGroupViewModel
|
||||
.GetAllKeyframePositions(false)
|
||||
.Select(p => p.TotalSeconds * _profileEditorService.PixelsPerSecond));
|
||||
}
|
||||
}
|
||||
}
|
||||
+72
-79
@@ -7,73 +7,23 @@ using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
{
|
||||
public class TimelineKeyframeViewModel<T> : TimelineKeyframeViewModel
|
||||
public class TimelineKeyframeViewModel<T> : Screen, IDisposable
|
||||
{
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
|
||||
public TimelineKeyframeViewModel(IProfileEditorService profileEditorService, LayerPropertyKeyframe<T> layerPropertyKeyframe)
|
||||
: base(profileEditorService, layerPropertyKeyframe)
|
||||
{
|
||||
_profileEditorService = profileEditorService;
|
||||
LayerPropertyKeyframe = layerPropertyKeyframe;
|
||||
}
|
||||
|
||||
public LayerPropertyKeyframe<T> LayerPropertyKeyframe { get; }
|
||||
|
||||
#region Context menu actions
|
||||
|
||||
public override void Copy()
|
||||
{
|
||||
var newKeyframe = new LayerPropertyKeyframe<T>(
|
||||
LayerPropertyKeyframe.Value,
|
||||
LayerPropertyKeyframe.Position,
|
||||
LayerPropertyKeyframe.EasingFunction,
|
||||
LayerPropertyKeyframe.LayerProperty
|
||||
);
|
||||
// If possible, shift the keyframe to the right by 11 pixels
|
||||
var desiredPosition = newKeyframe.Position + TimeSpan.FromMilliseconds(1000f / _profileEditorService.PixelsPerSecond * 11);
|
||||
if (desiredPosition <= newKeyframe.LayerProperty.ProfileElement.TimelineLength)
|
||||
newKeyframe.Position = desiredPosition;
|
||||
// Otherwise if possible shift it to the left by 11 pixels
|
||||
else
|
||||
{
|
||||
desiredPosition = newKeyframe.Position - TimeSpan.FromMilliseconds(1000f / _profileEditorService.PixelsPerSecond * 11);
|
||||
if (desiredPosition > TimeSpan.Zero)
|
||||
newKeyframe.Position = desiredPosition;
|
||||
}
|
||||
|
||||
LayerPropertyKeyframe.LayerProperty.AddKeyframe(newKeyframe);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
}
|
||||
|
||||
public override void Delete()
|
||||
{
|
||||
LayerPropertyKeyframe.LayerProperty.RemoveKeyframe(LayerPropertyKeyframe);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
public abstract class TimelineKeyframeViewModel : PropertyChangedBase, IDisposable
|
||||
{
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private BindableCollection<TimelineEasingViewModel> _easingViewModels;
|
||||
private bool _isSelected;
|
||||
private int _pixelsPerSecond;
|
||||
private string _timestamp;
|
||||
private double _x;
|
||||
|
||||
protected TimelineKeyframeViewModel(IProfileEditorService profileEditorService, BaseLayerPropertyKeyframe baseLayerPropertyKeyframe)
|
||||
public TimelineKeyframeViewModel(LayerPropertyKeyframe<T> layerPropertyKeyframe, IProfileEditorService profileEditorService)
|
||||
{
|
||||
_profileEditorService = profileEditorService;
|
||||
BaseLayerPropertyKeyframe = baseLayerPropertyKeyframe;
|
||||
EasingViewModels = new BindableCollection<TimelineEasingViewModel>();
|
||||
|
||||
BaseLayerPropertyKeyframe.PropertyChanged += BaseLayerPropertyKeyframeOnPropertyChanged;
|
||||
LayerPropertyKeyframe = layerPropertyKeyframe;
|
||||
LayerPropertyKeyframe.PropertyChanged += LayerPropertyKeyframeOnPropertyChanged;
|
||||
}
|
||||
|
||||
public BaseLayerPropertyKeyframe BaseLayerPropertyKeyframe { get; }
|
||||
public LayerPropertyKeyframe<T> LayerPropertyKeyframe { get; }
|
||||
|
||||
public BindableCollection<TimelineEasingViewModel> EasingViewModels
|
||||
{
|
||||
@@ -101,42 +51,51 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
BaseLayerPropertyKeyframe.PropertyChanged -= BaseLayerPropertyKeyframeOnPropertyChanged;
|
||||
LayerPropertyKeyframe.PropertyChanged -= LayerPropertyKeyframeOnPropertyChanged;
|
||||
|
||||
foreach (var timelineEasingViewModel in EasingViewModels)
|
||||
timelineEasingViewModel.EasingModeSelected -= TimelineEasingViewModelOnEasingModeSelected;
|
||||
}
|
||||
|
||||
public void Update(int pixelsPerSecond)
|
||||
public void Update()
|
||||
{
|
||||
_pixelsPerSecond = pixelsPerSecond;
|
||||
|
||||
X = pixelsPerSecond * BaseLayerPropertyKeyframe.Position.TotalSeconds;
|
||||
Timestamp = $"{Math.Floor(BaseLayerPropertyKeyframe.Position.TotalSeconds):00}.{BaseLayerPropertyKeyframe.Position.Milliseconds:000}";
|
||||
X = _profileEditorService.PixelsPerSecond * LayerPropertyKeyframe.Position.TotalSeconds;
|
||||
Timestamp = $"{Math.Floor(LayerPropertyKeyframe.Position.TotalSeconds):00}.{LayerPropertyKeyframe.Position.Milliseconds:000}";
|
||||
}
|
||||
|
||||
public abstract void Copy();
|
||||
|
||||
public abstract void Delete();
|
||||
|
||||
private void BaseLayerPropertyKeyframeOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
private void LayerPropertyKeyframeOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(BaseLayerPropertyKeyframe.Position))
|
||||
Update(_pixelsPerSecond);
|
||||
if (e.PropertyName == nameof(LayerPropertyKeyframe.Position))
|
||||
Update();
|
||||
}
|
||||
|
||||
#region Easing
|
||||
|
||||
public void CreateEasingViewModels()
|
||||
{
|
||||
EasingViewModels.AddRange(Enum.GetValues(typeof(Easings.Functions)).Cast<Easings.Functions>().Select(v => new TimelineEasingViewModel(this, v)));
|
||||
if (EasingViewModels.Any())
|
||||
return;
|
||||
|
||||
EasingViewModels.AddRange(Enum.GetValues(typeof(Easings.Functions))
|
||||
.Cast<Easings.Functions>()
|
||||
.Select(e => new TimelineEasingViewModel(e, e == LayerPropertyKeyframe.EasingFunction)));
|
||||
|
||||
foreach (var timelineEasingViewModel in EasingViewModels)
|
||||
timelineEasingViewModel.EasingModeSelected += TimelineEasingViewModelOnEasingModeSelected;
|
||||
}
|
||||
|
||||
private void TimelineEasingViewModelOnEasingModeSelected(object sender, EventArgs e)
|
||||
{
|
||||
SelectEasingMode((TimelineEasingViewModel) sender);
|
||||
}
|
||||
|
||||
public void SelectEasingMode(TimelineEasingViewModel easingViewModel)
|
||||
{
|
||||
BaseLayerPropertyKeyframe.EasingFunction = easingViewModel.EasingFunction;
|
||||
LayerPropertyKeyframe.EasingFunction = easingViewModel.EasingFunction;
|
||||
// Set every selection to false except on the VM that made the change
|
||||
foreach (var propertyTrackEasingViewModel in EasingViewModels.Where(vm => vm != easingViewModel))
|
||||
propertyTrackEasingViewModel.IsEasingModeSelected = false;
|
||||
|
||||
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
}
|
||||
|
||||
@@ -151,7 +110,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
_offset = null;
|
||||
}
|
||||
|
||||
public void SaveOffsetToKeyframe(TimelineKeyframeViewModel keyframeViewModel)
|
||||
public void SaveOffsetToKeyframe(TimelineKeyframeViewModel<T> keyframeViewModel)
|
||||
{
|
||||
if (keyframeViewModel == this)
|
||||
{
|
||||
@@ -162,27 +121,61 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
if (_offset != null)
|
||||
return;
|
||||
|
||||
_offset = BaseLayerPropertyKeyframe.Position - keyframeViewModel.BaseLayerPropertyKeyframe.Position;
|
||||
_offset = LayerPropertyKeyframe.Position - keyframeViewModel.LayerPropertyKeyframe.Position;
|
||||
}
|
||||
|
||||
public void ApplyOffsetToKeyframe(TimelineKeyframeViewModel keyframeViewModel)
|
||||
public void ApplyOffsetToKeyframe(TimelineKeyframeViewModel<T> keyframeViewModel)
|
||||
{
|
||||
if (keyframeViewModel == this || _offset == null)
|
||||
return;
|
||||
|
||||
UpdatePosition(keyframeViewModel.BaseLayerPropertyKeyframe.Position + _offset.Value);
|
||||
UpdatePosition(keyframeViewModel.LayerPropertyKeyframe.Position + _offset.Value);
|
||||
}
|
||||
|
||||
public void UpdatePosition(TimeSpan position)
|
||||
{
|
||||
if (position < TimeSpan.Zero)
|
||||
BaseLayerPropertyKeyframe.Position = TimeSpan.Zero;
|
||||
LayerPropertyKeyframe.Position = TimeSpan.Zero;
|
||||
else if (position > _profileEditorService.SelectedProfileElement.TimelineLength)
|
||||
BaseLayerPropertyKeyframe.Position = _profileEditorService.SelectedProfileElement.TimelineLength;
|
||||
LayerPropertyKeyframe.Position = _profileEditorService.SelectedProfileElement.TimelineLength;
|
||||
else
|
||||
BaseLayerPropertyKeyframe.Position = position;
|
||||
LayerPropertyKeyframe.Position = position;
|
||||
|
||||
Update(_pixelsPerSecond);
|
||||
Update();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Context menu actions
|
||||
|
||||
public void Copy()
|
||||
{
|
||||
var newKeyframe = new LayerPropertyKeyframe<T>(
|
||||
LayerPropertyKeyframe.Value,
|
||||
LayerPropertyKeyframe.Position,
|
||||
LayerPropertyKeyframe.EasingFunction,
|
||||
LayerPropertyKeyframe.LayerProperty
|
||||
);
|
||||
// If possible, shift the keyframe to the right by 11 pixels
|
||||
var desiredPosition = newKeyframe.Position + TimeSpan.FromMilliseconds(1000f / _profileEditorService.PixelsPerSecond * 11);
|
||||
if (desiredPosition <= newKeyframe.LayerProperty.ProfileElement.TimelineLength)
|
||||
newKeyframe.Position = desiredPosition;
|
||||
// Otherwise if possible shift it to the left by 11 pixels
|
||||
else
|
||||
{
|
||||
desiredPosition = newKeyframe.Position - TimeSpan.FromMilliseconds(1000f / _profileEditorService.PixelsPerSecond * 11);
|
||||
if (desiredPosition > TimeSpan.Zero)
|
||||
newKeyframe.Position = desiredPosition;
|
||||
}
|
||||
|
||||
LayerPropertyKeyframe.LayerProperty.AddKeyframe(newKeyframe);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
}
|
||||
|
||||
public void Delete()
|
||||
{
|
||||
LayerPropertyKeyframe.LayerProperty.RemoveKeyframe(LayerPropertyKeyframe);
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
-59
@@ -1,59 +0,0 @@
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Linq;
|
||||
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Abstract;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
{
|
||||
public class TimelinePropertyGroupViewModel : PropertyChangedBase
|
||||
{
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private BindableCollection<double> _timelineKeyframeViewModels;
|
||||
|
||||
public TimelinePropertyGroupViewModel(LayerPropertyBaseViewModel layerPropertyBaseViewModel, IProfileEditorService profileEditorService)
|
||||
{
|
||||
_profileEditorService = profileEditorService;
|
||||
LayerPropertyGroupViewModel = (LayerPropertyGroupViewModel) layerPropertyBaseViewModel;
|
||||
TimelineKeyframeViewModels = new BindableCollection<double>();
|
||||
|
||||
LayerPropertyGroupViewModel.ProfileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||
LayerPropertyGroupViewModel.PropertyChanged += LayerPropertyGroupViewModelOnPropertyChanged;
|
||||
UpdateKeyframes();
|
||||
}
|
||||
|
||||
public LayerPropertyGroupViewModel LayerPropertyGroupViewModel { get; }
|
||||
|
||||
public BindableCollection<double> TimelineKeyframeViewModels
|
||||
{
|
||||
get => _timelineKeyframeViewModels;
|
||||
set => SetAndNotify(ref _timelineKeyframeViewModels, value);
|
||||
}
|
||||
|
||||
public void UpdateKeyframes()
|
||||
{
|
||||
TimelineKeyframeViewModels.Clear();
|
||||
TimelineKeyframeViewModels.AddRange(LayerPropertyGroupViewModel.GetKeyframes(false)
|
||||
.Select(k => LayerPropertyGroupViewModel.ProfileEditorService.PixelsPerSecond * k.Position.TotalSeconds));
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
LayerPropertyGroupViewModel.ProfileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||
LayerPropertyGroupViewModel.PropertyChanged -= LayerPropertyGroupViewModelOnPropertyChanged;
|
||||
}
|
||||
|
||||
private void LayerPropertyGroupViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(LayerPropertyGroupViewModel.IsExpanded))
|
||||
UpdateKeyframes();
|
||||
}
|
||||
|
||||
private void ProfileEditorServiceOnPixelsPerSecondChanged(object sender, EventArgs e)
|
||||
{
|
||||
UpdateKeyframes();
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-2
@@ -9,12 +9,11 @@
|
||||
xmlns:timeline="clr-namespace:Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:TimelinePropertyViewModel}"
|
||||
Visibility="{Binding LayerPropertyBaseViewModel.IsVisible, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"
|
||||
MinWidth="{Binding Width}"
|
||||
HorizontalAlignment="Stretch">
|
||||
<Border Height="25" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource MaterialDesignDivider}">
|
||||
<ItemsControl ItemsSource="{Binding TimelineKeyframeViewModels}"
|
||||
<ItemsControl ItemsSource="{Binding Items}"
|
||||
Background="{DynamicResource MaterialDesignToolBarBackground}"
|
||||
HorizontalAlignment="Left">
|
||||
<ItemsControl.ItemsPanel>
|
||||
|
||||
+26
-73
@@ -1,108 +1,61 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Abstract;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
{
|
||||
public class TimelinePropertyViewModel<T> : TimelinePropertyViewModel
|
||||
public class TimelinePropertyViewModel<T> : Conductor<TimelineKeyframeViewModel<T>>.Collection.AllActive, ITimelinePropertyViewModel
|
||||
{
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
public LayerProperty<T> LayerProperty { get; }
|
||||
public LayerPropertyViewModel LayerPropertyViewModel { get; }
|
||||
|
||||
public TimelinePropertyViewModel(LayerPropertyBaseViewModel layerPropertyBaseViewModel, IProfileEditorService profileEditorService) : base(layerPropertyBaseViewModel)
|
||||
public TimelinePropertyViewModel(LayerProperty<T> layerProperty, LayerPropertyViewModel layerPropertyViewModel, IProfileEditorService profileEditorService)
|
||||
{
|
||||
_profileEditorService = profileEditorService;
|
||||
LayerPropertyViewModel = (LayerPropertyViewModel<T>) layerPropertyBaseViewModel;
|
||||
|
||||
LayerPropertyViewModel.LayerProperty.KeyframeAdded += LayerPropertyOnKeyframeModified;
|
||||
LayerPropertyViewModel.LayerProperty.KeyframeRemoved += LayerPropertyOnKeyframeModified;
|
||||
LayerPropertyViewModel.LayerProperty.KeyframesToggled += LayerPropertyOnKeyframeModified;
|
||||
_profileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||
LayerProperty = layerProperty;
|
||||
LayerPropertyViewModel = layerPropertyViewModel;
|
||||
}
|
||||
|
||||
public LayerPropertyViewModel<T> LayerPropertyViewModel { get; }
|
||||
public List<TimeSpan> GetAllKeyframePositions()
|
||||
{
|
||||
return LayerProperty.Keyframes.Select(k => k.Position).ToList();
|
||||
}
|
||||
|
||||
public override void UpdateKeyframes()
|
||||
private void UpdateKeyframes()
|
||||
{
|
||||
// Only show keyframes if they are enabled
|
||||
if (LayerPropertyViewModel.LayerProperty.KeyframesEnabled)
|
||||
if (LayerProperty.KeyframesEnabled)
|
||||
{
|
||||
var keyframes = LayerPropertyViewModel.LayerProperty.Keyframes.ToList();
|
||||
var toRemove = TimelineKeyframeViewModels.Where(t => !keyframes.Contains(t.BaseLayerPropertyKeyframe)).ToList();
|
||||
var keyframes = LayerProperty.Keyframes.ToList();
|
||||
var toRemove = Items.Where(t => !keyframes.Contains(t.LayerPropertyKeyframe)).ToList();
|
||||
foreach (var timelineKeyframeViewModel in toRemove)
|
||||
timelineKeyframeViewModel.Dispose();
|
||||
|
||||
TimelineKeyframeViewModels.RemoveRange(toRemove);
|
||||
TimelineKeyframeViewModels.AddRange(keyframes
|
||||
.Where(k => TimelineKeyframeViewModels.All(t => t.BaseLayerPropertyKeyframe != k))
|
||||
.Select(k => new TimelineKeyframeViewModel<T>(_profileEditorService, k))
|
||||
Items.RemoveRange(toRemove);
|
||||
Items.AddRange(keyframes
|
||||
.Where(k => Items.All(t => t.LayerPropertyKeyframe != k))
|
||||
.Select(k => new TimelineKeyframeViewModel<T>(k, _profileEditorService))
|
||||
);
|
||||
}
|
||||
else
|
||||
DisposeKeyframeViewModels();
|
||||
Items.Clear();
|
||||
|
||||
foreach (var timelineKeyframeViewModel in TimelineKeyframeViewModels)
|
||||
timelineKeyframeViewModel.Update(_profileEditorService.PixelsPerSecond);
|
||||
foreach (var timelineKeyframeViewModel in Items)
|
||||
timelineKeyframeViewModel.Update();
|
||||
}
|
||||
|
||||
public override void Dispose()
|
||||
public void Dispose()
|
||||
{
|
||||
_profileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||
LayerPropertyViewModel.LayerProperty.KeyframeAdded -= LayerPropertyOnKeyframeModified;
|
||||
LayerPropertyViewModel.LayerProperty.KeyframeRemoved -= LayerPropertyOnKeyframeModified;
|
||||
LayerPropertyViewModel.LayerProperty.KeyframesToggled -= LayerPropertyOnKeyframeModified;
|
||||
DisposeKeyframeViewModels();
|
||||
}
|
||||
|
||||
private void DisposeKeyframeViewModels()
|
||||
{
|
||||
foreach (var timelineKeyframeViewModel in TimelineKeyframeViewModels)
|
||||
timelineKeyframeViewModel.Dispose();
|
||||
TimelineKeyframeViewModels.Clear();
|
||||
}
|
||||
|
||||
private void LayerPropertyOnKeyframeModified(object sender, EventArgs e)
|
||||
{
|
||||
UpdateKeyframes();
|
||||
}
|
||||
|
||||
private void ProfileEditorServiceOnPixelsPerSecondChanged(object sender, EventArgs e)
|
||||
{
|
||||
foreach (var timelineKeyframeViewModel in TimelineKeyframeViewModels)
|
||||
timelineKeyframeViewModel.Update(_profileEditorService.PixelsPerSecond);
|
||||
|
||||
Width = TimelineKeyframeViewModels.Any() ? TimelineKeyframeViewModels.Max(t => t.X) + 25 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract class TimelinePropertyViewModel : PropertyChangedBase, IDisposable
|
||||
public interface ITimelinePropertyViewModel : IScreen, IDisposable
|
||||
{
|
||||
private BindableCollection<TimelineKeyframeViewModel> _timelineKeyframeViewModels;
|
||||
private double _width;
|
||||
|
||||
protected TimelinePropertyViewModel(LayerPropertyBaseViewModel layerPropertyBaseViewModel)
|
||||
{
|
||||
LayerPropertyBaseViewModel = layerPropertyBaseViewModel;
|
||||
TimelineKeyframeViewModels = new BindableCollection<TimelineKeyframeViewModel>();
|
||||
}
|
||||
|
||||
public LayerPropertyBaseViewModel LayerPropertyBaseViewModel { get; }
|
||||
|
||||
public BindableCollection<TimelineKeyframeViewModel> TimelineKeyframeViewModels
|
||||
{
|
||||
get => _timelineKeyframeViewModels;
|
||||
set => SetAndNotify(ref _timelineKeyframeViewModels, value);
|
||||
}
|
||||
|
||||
public double Width
|
||||
{
|
||||
get => _width;
|
||||
set => SetAndNotify(ref _width, value);
|
||||
}
|
||||
|
||||
public abstract void Dispose();
|
||||
|
||||
public abstract void UpdateKeyframes();
|
||||
List<TimeSpan> GetAllKeyframePositions();
|
||||
}
|
||||
}
|
||||
@@ -8,7 +8,6 @@ using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Abstract;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Stylet;
|
||||
@@ -32,8 +31,6 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
|
||||
SelectedProfileElement.PropertyChanged += SelectedProfileElementOnPropertyChanged;
|
||||
_profileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||
|
||||
Update();
|
||||
}
|
||||
|
||||
public RenderProfileElement SelectedProfileElement { get; set; }
|
||||
@@ -62,21 +59,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||
_profileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||
SelectedProfileElement.PropertyChanged -= SelectedProfileElementOnPropertyChanged;
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
foreach (var layerPropertyGroupViewModel in LayerPropertyGroups)
|
||||
{
|
||||
layerPropertyGroupViewModel.TimelinePropertyGroupViewModel.UpdateKeyframes();
|
||||
|
||||
foreach (var layerPropertyBaseViewModel in layerPropertyGroupViewModel.GetAllChildren())
|
||||
{
|
||||
if (layerPropertyBaseViewModel is LayerPropertyViewModel layerPropertyViewModel)
|
||||
layerPropertyViewModel.TimelinePropertyBaseViewModel.UpdateKeyframes();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private void SelectedProfileElementOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(_profileEditorService.SelectedProfileElement.StartSegmentLength))
|
||||
|
||||
Reference in new issue
Block a user