mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-01-02 10:43:31 +00:00
Profile editor - Reimplementing the timeline
This commit is contained in:
parent
3009a793dd
commit
13a006ba48
@ -80,8 +80,9 @@ namespace Artemis.UI.Ninject.Factories
|
|||||||
{
|
{
|
||||||
LayerPropertyViewModel LayerPropertyViewModel(ILayerProperty layerProperty);
|
LayerPropertyViewModel LayerPropertyViewModel(ILayerProperty layerProperty);
|
||||||
LayerPropertyGroupViewModel LayerPropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup);
|
LayerPropertyGroupViewModel LayerPropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup);
|
||||||
LayerPropertyTreeViewModel<T> LayerPropertyGroupViewModel<T>(LayerProperty<T> layerProperty);
|
TreePropertyViewModel<T> LayerPropertyGroupViewModel<T>(LayerProperty<T> layerProperty);
|
||||||
LayerPropertyGroupTreeViewModel LayerPropertyGroupTreeViewModel(LayerPropertyGroupViewModel layerPropertyGroupViewModel);
|
TreeGroupViewModel TreeGroupViewModel(LayerPropertyGroupViewModel layerPropertyGroupViewModel);
|
||||||
|
TimelineGroupViewModel TimelineGroupViewModel(LayerPropertyGroupViewModel layerPropertyGroupViewModel);
|
||||||
LayerPropertyGroupViewModel LayerPropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, PropertyGroupDescriptionAttribute propertyGroupDescription);
|
LayerPropertyGroupViewModel LayerPropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, PropertyGroupDescriptionAttribute propertyGroupDescription);
|
||||||
TreeViewModel TreeViewModel(LayerPropertiesViewModel layerPropertiesViewModel, BindableCollection<LayerPropertyGroupViewModel> layerPropertyGroups);
|
TreeViewModel TreeViewModel(LayerPropertiesViewModel layerPropertiesViewModel, BindableCollection<LayerPropertyGroupViewModel> layerPropertyGroups);
|
||||||
EffectsViewModel EffectsViewModel(LayerPropertiesViewModel layerPropertiesViewModel);
|
EffectsViewModel EffectsViewModel(LayerPropertiesViewModel layerPropertiesViewModel);
|
||||||
|
|||||||
@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Reflection;
|
||||||
|
using Ninject.Extensions.Factory;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Ninject.InstanceProviders
|
||||||
|
{
|
||||||
|
public class DataBindingsViewModelInstanceProvider : StandardInstanceProvider
|
||||||
|
{
|
||||||
|
protected override Type GetType(MethodInfo methodInfo, object[] arguments)
|
||||||
|
{
|
||||||
|
return base.GetType(methodInfo, arguments);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -16,7 +16,7 @@ using Artemis.UI.Shared;
|
|||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using GongSolutions.Wpf.DragDrop;
|
using GongSolutions.Wpf.DragDrop;
|
||||||
using Stylet;
|
using Stylet;
|
||||||
using static Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree.LayerPropertyGroupTreeViewModel.LayerPropertyGroupType;
|
using static Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree.TreeGroupViewModel.LayerPropertyGroupType;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
||||||
{
|
{
|
||||||
@ -246,7 +246,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
|||||||
{
|
{
|
||||||
RightSideIndex = 1;
|
RightSideIndex = 1;
|
||||||
DataBindingsViewModel?.Dispose();
|
DataBindingsViewModel?.Dispose();
|
||||||
DataBindingsViewModel = _dataBindingsVmFactory.DataBindingsViewModel(ProfileEditorService.SelectedDataBinding);
|
// TODO
|
||||||
|
// DataBindingsViewModel = _dataBindingsVmFactory.DataBindingsViewModel(ProfileEditorService.SelectedDataBinding);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
RightSideIndex = 0;
|
RightSideIndex = 0;
|
||||||
@ -357,7 +358,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
|||||||
}
|
}
|
||||||
|
|
||||||
SortProperties();
|
SortProperties();
|
||||||
UpdateKeyframes();
|
TimelineViewModel.Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ApplyEffects()
|
private void ApplyEffects()
|
||||||
@ -392,18 +393,18 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
|||||||
}
|
}
|
||||||
|
|
||||||
SortProperties();
|
SortProperties();
|
||||||
UpdateKeyframes();
|
TimelineViewModel.Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SortProperties()
|
private void SortProperties()
|
||||||
{
|
{
|
||||||
// Get all non-effect properties
|
// Get all non-effect properties
|
||||||
var nonEffectProperties = LayerPropertyGroups
|
var nonEffectProperties = LayerPropertyGroups
|
||||||
.Where(l => l.LayerPropertyGroupTreeViewModel.GroupType != LayerEffectRoot)
|
.Where(l => l.TreeGroupViewModel.GroupType != LayerEffectRoot)
|
||||||
.ToList();
|
.ToList();
|
||||||
// Order the effects
|
// Order the effects
|
||||||
var effectProperties = LayerPropertyGroups
|
var effectProperties = LayerPropertyGroups
|
||||||
.Where(l => l.LayerPropertyGroupTreeViewModel.GroupType == LayerEffectRoot)
|
.Where(l => l.TreeGroupViewModel.GroupType == LayerEffectRoot)
|
||||||
.OrderBy(l => l.LayerPropertyGroup.LayerEffect.Order)
|
.OrderBy(l => l.LayerPropertyGroup.LayerEffect.Order)
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
@ -422,11 +423,6 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateKeyframes()
|
|
||||||
{
|
|
||||||
TimelineViewModel.Update();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Drag and drop
|
#region Drag and drop
|
||||||
@ -442,8 +438,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
|||||||
var target = dropInfo.TargetItem as LayerPropertyGroupViewModel;
|
var target = dropInfo.TargetItem as LayerPropertyGroupViewModel;
|
||||||
|
|
||||||
if (source == target ||
|
if (source == target ||
|
||||||
target?.LayerPropertyGroupTreeViewModel.GroupType != LayerEffectRoot ||
|
target?.TreeGroupViewModel.GroupType != LayerEffectRoot ||
|
||||||
source?.LayerPropertyGroupTreeViewModel.GroupType != LayerEffectRoot)
|
source?.TreeGroupViewModel.GroupType != LayerEffectRoot)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
dropInfo.DropTargetAdorner = DropTargetAdorners.Insert;
|
dropInfo.DropTargetAdorner = DropTargetAdorners.Insert;
|
||||||
@ -461,8 +457,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
|||||||
var target = dropInfo.TargetItem as LayerPropertyGroupViewModel;
|
var target = dropInfo.TargetItem as LayerPropertyGroupViewModel;
|
||||||
|
|
||||||
if (source == target ||
|
if (source == target ||
|
||||||
target?.LayerPropertyGroupTreeViewModel.GroupType != LayerEffectRoot ||
|
target?.TreeGroupViewModel.GroupType != LayerEffectRoot ||
|
||||||
source?.LayerPropertyGroupTreeViewModel.GroupType != LayerEffectRoot)
|
source?.TreeGroupViewModel.GroupType != LayerEffectRoot)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (dropInfo.InsertPosition == RelativeInsertPosition.BeforeTargetItem)
|
if (dropInfo.InsertPosition == RelativeInsertPosition.BeforeTargetItem)
|
||||||
@ -491,7 +487,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
|||||||
private void ApplyCurrentEffectsOrder()
|
private void ApplyCurrentEffectsOrder()
|
||||||
{
|
{
|
||||||
var order = 1;
|
var order = 1;
|
||||||
foreach (var groupViewModel in LayerPropertyGroups.Where(p => p.LayerPropertyGroupTreeViewModel.GroupType == LayerEffectRoot))
|
foreach (var groupViewModel in LayerPropertyGroups.Where(p => p.TreeGroupViewModel.GroupType == LayerEffectRoot))
|
||||||
{
|
{
|
||||||
groupViewModel.UpdateOrder(order);
|
groupViewModel.UpdateOrder(order);
|
||||||
order++;
|
order++;
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.UI.Ninject.Factories;
|
using Artemis.UI.Ninject.Factories;
|
||||||
|
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline;
|
||||||
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree;
|
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree;
|
||||||
using Stylet;
|
using Stylet;
|
||||||
|
|
||||||
@ -16,13 +17,17 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
|||||||
_layerPropertyVmFactory = layerPropertyVmFactory;
|
_layerPropertyVmFactory = layerPropertyVmFactory;
|
||||||
|
|
||||||
LayerPropertyGroup = layerPropertyGroup;
|
LayerPropertyGroup = layerPropertyGroup;
|
||||||
LayerPropertyGroupTreeViewModel = layerPropertyVmFactory.LayerPropertyGroupTreeViewModel(this);
|
Children = new BindableCollection<PropertyChangedBase>();
|
||||||
|
|
||||||
|
TreeGroupViewModel = layerPropertyVmFactory.TreeGroupViewModel(this);
|
||||||
|
TimelineGroupViewModel = layerPropertyVmFactory.TimelineGroupViewModel(this);
|
||||||
PopulateChildren();
|
PopulateChildren();
|
||||||
}
|
}
|
||||||
|
|
||||||
public LayerPropertyGroup LayerPropertyGroup { get; }
|
public LayerPropertyGroup LayerPropertyGroup { get; }
|
||||||
public LayerPropertyGroupTreeViewModel LayerPropertyGroupTreeViewModel { get; }
|
public TreeGroupViewModel TreeGroupViewModel { get; }
|
||||||
public BindableCollection<PropertyChangedBase> Children { get; set; }
|
public TimelineGroupViewModel TimelineGroupViewModel { get; }
|
||||||
|
public BindableCollection<PropertyChangedBase> Children { get; }
|
||||||
|
|
||||||
public bool IsVisible => !LayerPropertyGroup.IsHidden;
|
public bool IsVisible => !LayerPropertyGroup.IsHidden;
|
||||||
|
|
||||||
@ -51,7 +56,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
|||||||
{
|
{
|
||||||
var layerPropertyViewModel = _layerPropertyVmFactory.LayerPropertyViewModel(layerProperty);
|
var layerPropertyViewModel = _layerPropertyVmFactory.LayerPropertyViewModel(layerProperty);
|
||||||
// After creation ensure a supported input VM was found, if not, discard the VM
|
// After creation ensure a supported input VM was found, if not, discard the VM
|
||||||
if (!layerPropertyViewModel.LayerPropertyTreeViewModel.HasPropertyInputViewModel)
|
if (!layerPropertyViewModel.TreePropertyViewModel.HasPropertyInputViewModel)
|
||||||
layerPropertyViewModel.Dispose();
|
layerPropertyViewModel.Dispose();
|
||||||
else
|
else
|
||||||
Children.Add(layerPropertyViewModel);
|
Children.Add(layerPropertyViewModel);
|
||||||
@ -86,7 +91,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
|||||||
foreach (var child in Children)
|
foreach (var child in Children)
|
||||||
{
|
{
|
||||||
if (child is LayerPropertyViewModel layerPropertyViewModel)
|
if (child is LayerPropertyViewModel layerPropertyViewModel)
|
||||||
result.AddRange(layerPropertyViewModel.LayerPropertyTimelineViewModel.GetAllKeyframePositions());
|
result.AddRange(layerPropertyViewModel.TimelinePropertyViewModel.GetAllKeyframePositions());
|
||||||
else if (child is LayerPropertyGroupViewModel layerPropertyGroupViewModel)
|
else if (child is LayerPropertyGroupViewModel layerPropertyGroupViewModel)
|
||||||
result.AddRange(layerPropertyGroupViewModel.GetAllKeyframePositions(expandedOnly));
|
result.AddRange(layerPropertyGroupViewModel.GetAllKeyframePositions(expandedOnly));
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
|
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline;
|
||||||
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree;
|
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree;
|
||||||
using Ninject;
|
using Ninject;
|
||||||
using Ninject.Parameters;
|
using Ninject.Parameters;
|
||||||
@ -14,24 +15,24 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
|||||||
LayerProperty = layerProperty;
|
LayerProperty = layerProperty;
|
||||||
|
|
||||||
var parameter = new ConstructorArgument("layerProperty", LayerProperty);
|
var parameter = new ConstructorArgument("layerProperty", LayerProperty);
|
||||||
var treeViewModelType = typeof(LayerPropertyTreeViewModel<>).MakeGenericType(layerProperty.GetType().GetGenericArguments());
|
var treeViewModelType = typeof(TreePropertyViewModel<>).MakeGenericType(layerProperty.GetType().GetGenericArguments());
|
||||||
var timelineViewModelType = typeof(LayerPropertyTimelineViewModel<>).MakeGenericType(layerProperty.GetType().GetGenericArguments());
|
var timelineViewModelType = typeof(TimelinePropertyViewModel<>).MakeGenericType(layerProperty.GetType().GetGenericArguments());
|
||||||
|
|
||||||
LayerPropertyTreeViewModel = (ILayerPropertyTreeViewModel) kernel.Get(treeViewModelType, parameter);
|
TreePropertyViewModel = (ITreePropertyViewModel) kernel.Get(treeViewModelType, parameter);
|
||||||
LayerPropertyTimelineViewModel = (ILayerPropertyTimelineViewModel) kernel.Get(timelineViewModelType, parameter);
|
TimelinePropertyViewModel = (ITimelinePropertyViewModel) kernel.Get(timelineViewModelType, parameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ILayerProperty LayerProperty { get; }
|
public ILayerProperty LayerProperty { get; }
|
||||||
public ILayerPropertyTreeViewModel LayerPropertyTreeViewModel { get; }
|
public ITreePropertyViewModel TreePropertyViewModel { get; }
|
||||||
public ILayerPropertyTimelineViewModel LayerPropertyTimelineViewModel { get; }
|
public ITimelinePropertyViewModel TimelinePropertyViewModel { get; }
|
||||||
|
|
||||||
public bool IsVisible { get; set; }
|
public bool IsVisible { get; set; }
|
||||||
public bool IsExpanded { get; set; }
|
public bool IsExpanded { get; set; }
|
||||||
|
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
LayerPropertyTreeViewModel?.Dispose();
|
TreePropertyViewModel?.Dispose();
|
||||||
LayerPropertyTimelineViewModel?.Dispose();
|
TimelinePropertyViewModel?.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,4 +1,5 @@
|
|||||||
using System.Windows;
|
using System;
|
||||||
|
using System.Windows;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Humanizer;
|
using Humanizer;
|
||||||
@ -7,17 +8,11 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
|||||||
{
|
{
|
||||||
public class TimelineEasingViewModel
|
public class TimelineEasingViewModel
|
||||||
{
|
{
|
||||||
private readonly TimelineKeyframeViewModel _keyframeViewModel;
|
|
||||||
private bool _isEasingModeSelected;
|
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
|
_isEasingModeSelected = isSelected;
|
||||||
if (keyframeViewModel != null)
|
|
||||||
{
|
|
||||||
_keyframeViewModel = keyframeViewModel;
|
|
||||||
_isEasingModeSelected = keyframeViewModel.BaseLayerPropertyKeyframe.EasingFunction == easingFunction;
|
|
||||||
}
|
|
||||||
|
|
||||||
EasingFunction = easingFunction;
|
EasingFunction = easingFunction;
|
||||||
Description = easingFunction.Humanize();
|
Description = easingFunction.Humanize();
|
||||||
@ -41,9 +36,15 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
|||||||
set
|
set
|
||||||
{
|
{
|
||||||
_isEasingModeSelected = value;
|
_isEasingModeSelected = value;
|
||||||
if (_isEasingModeSelected)
|
if (value) OnEasingModeSelected();
|
||||||
_keyframeViewModel.SelectEasingMode(this);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public event EventHandler EasingModeSelected;
|
||||||
|
|
||||||
|
protected virtual void OnEasingModeSelected()
|
||||||
|
{
|
||||||
|
EasingModeSelected?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -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="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline"
|
xmlns:local="clr-namespace:Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline"
|
||||||
xmlns:s="https://github.com/canton7/Stylet"
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
xmlns:layerProperties1="clr-namespace:Artemis.UI.Screens.ProfileEditor.LayerProperties"
|
xmlns:layerProperties="clr-namespace:Artemis.UI.Screens.ProfileEditor.LayerProperties"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800"
|
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}">
|
Visibility="{Binding LayerPropertyGroupViewModel.IsVisible, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
@ -20,7 +20,7 @@
|
|||||||
<ItemsControl Grid.Row="0"
|
<ItemsControl Grid.Row="0"
|
||||||
Height="24"
|
Height="24"
|
||||||
Visibility="{Binding LayerPropertyGroupViewModel.IsExpanded, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}"
|
Visibility="{Binding LayerPropertyGroupViewModel.IsExpanded, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}"
|
||||||
ItemsSource="{Binding TimelineKeyframeViewModels}"
|
ItemsSource="{Binding KeyframePositions}"
|
||||||
Background="{DynamicResource MaterialDesignToolBarBackground}"
|
Background="{DynamicResource MaterialDesignToolBarBackground}"
|
||||||
HorizontalAlignment="Stretch">
|
HorizontalAlignment="Stretch">
|
||||||
<ItemsControl.ItemsPanel>
|
<ItemsControl.ItemsPanel>
|
||||||
@ -59,14 +59,13 @@
|
|||||||
</Style>
|
</Style>
|
||||||
</ItemsControl.ItemContainerStyle>
|
</ItemsControl.ItemContainerStyle>
|
||||||
<ItemsControl.Resources>
|
<ItemsControl.Resources>
|
||||||
<DataTemplate DataType="{x:Type layerProperties1:LayerPropertyGroupViewModel}">
|
<DataTemplate DataType="{x:Type layerProperties:LayerPropertyGroupViewModel}">
|
||||||
<ContentControl s:View.Model="{Binding TimelinePropertyGroupViewModel}" IsTabStop="False" HorizontalAlignment="Stretch" />
|
<ContentControl s:View.Model="{Binding TimelineGroupViewModel}" IsTabStop="False" HorizontalAlignment="Stretch" />
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
<DataTemplate DataType="{x:Type layerProperties1:LayerPropertyViewModel}">
|
<DataTemplate DataType="{x:Type layerProperties:LayerPropertyViewModel}">
|
||||||
<ContentControl s:View.Model="{Binding TimelinePropertyBaseViewModel}" IsTabStop="False" HorizontalAlignment="Stretch" />
|
<ContentControl s:View.Model="{Binding TimelinePropertyViewModel}" IsTabStop="False" HorizontalAlignment="Stretch" />
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.Resources>
|
</ItemsControl.Resources>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -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));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -7,73 +7,23 @@ using Stylet;
|
|||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
||||||
{
|
{
|
||||||
public class TimelineKeyframeViewModel<T> : TimelineKeyframeViewModel
|
public class TimelineKeyframeViewModel<T> : Screen, IDisposable
|
||||||
{
|
{
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
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 BindableCollection<TimelineEasingViewModel> _easingViewModels;
|
||||||
private bool _isSelected;
|
private bool _isSelected;
|
||||||
private int _pixelsPerSecond;
|
|
||||||
private string _timestamp;
|
private string _timestamp;
|
||||||
private double _x;
|
private double _x;
|
||||||
|
|
||||||
protected TimelineKeyframeViewModel(IProfileEditorService profileEditorService, BaseLayerPropertyKeyframe baseLayerPropertyKeyframe)
|
public TimelineKeyframeViewModel(LayerPropertyKeyframe<T> layerPropertyKeyframe, IProfileEditorService profileEditorService)
|
||||||
{
|
{
|
||||||
_profileEditorService = profileEditorService;
|
_profileEditorService = profileEditorService;
|
||||||
BaseLayerPropertyKeyframe = baseLayerPropertyKeyframe;
|
LayerPropertyKeyframe = layerPropertyKeyframe;
|
||||||
EasingViewModels = new BindableCollection<TimelineEasingViewModel>();
|
LayerPropertyKeyframe.PropertyChanged += LayerPropertyKeyframeOnPropertyChanged;
|
||||||
|
|
||||||
BaseLayerPropertyKeyframe.PropertyChanged += BaseLayerPropertyKeyframeOnPropertyChanged;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public BaseLayerPropertyKeyframe BaseLayerPropertyKeyframe { get; }
|
public LayerPropertyKeyframe<T> LayerPropertyKeyframe { get; }
|
||||||
|
|
||||||
public BindableCollection<TimelineEasingViewModel> EasingViewModels
|
public BindableCollection<TimelineEasingViewModel> EasingViewModels
|
||||||
{
|
{
|
||||||
@ -101,42 +51,51 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
|||||||
|
|
||||||
public void Dispose()
|
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 = _profileEditorService.PixelsPerSecond * LayerPropertyKeyframe.Position.TotalSeconds;
|
||||||
|
Timestamp = $"{Math.Floor(LayerPropertyKeyframe.Position.TotalSeconds):00}.{LayerPropertyKeyframe.Position.Milliseconds:000}";
|
||||||
X = pixelsPerSecond * BaseLayerPropertyKeyframe.Position.TotalSeconds;
|
|
||||||
Timestamp = $"{Math.Floor(BaseLayerPropertyKeyframe.Position.TotalSeconds):00}.{BaseLayerPropertyKeyframe.Position.Milliseconds:000}";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract void Copy();
|
private void LayerPropertyKeyframeOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
|
|
||||||
public abstract void Delete();
|
|
||||||
|
|
||||||
private void BaseLayerPropertyKeyframeOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
{
|
||||||
if (e.PropertyName == nameof(BaseLayerPropertyKeyframe.Position))
|
if (e.PropertyName == nameof(LayerPropertyKeyframe.Position))
|
||||||
Update(_pixelsPerSecond);
|
Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Easing
|
#region Easing
|
||||||
|
|
||||||
public void CreateEasingViewModels()
|
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)
|
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
|
// Set every selection to false except on the VM that made the change
|
||||||
foreach (var propertyTrackEasingViewModel in EasingViewModels.Where(vm => vm != easingViewModel))
|
foreach (var propertyTrackEasingViewModel in EasingViewModels.Where(vm => vm != easingViewModel))
|
||||||
propertyTrackEasingViewModel.IsEasingModeSelected = false;
|
propertyTrackEasingViewModel.IsEasingModeSelected = false;
|
||||||
|
|
||||||
|
|
||||||
_profileEditorService.UpdateSelectedProfileElement();
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -151,7 +110,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
|||||||
_offset = null;
|
_offset = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void SaveOffsetToKeyframe(TimelineKeyframeViewModel keyframeViewModel)
|
public void SaveOffsetToKeyframe(TimelineKeyframeViewModel<T> keyframeViewModel)
|
||||||
{
|
{
|
||||||
if (keyframeViewModel == this)
|
if (keyframeViewModel == this)
|
||||||
{
|
{
|
||||||
@ -162,27 +121,61 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
|||||||
if (_offset != null)
|
if (_offset != null)
|
||||||
return;
|
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)
|
if (keyframeViewModel == this || _offset == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
UpdatePosition(keyframeViewModel.BaseLayerPropertyKeyframe.Position + _offset.Value);
|
UpdatePosition(keyframeViewModel.LayerPropertyKeyframe.Position + _offset.Value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void UpdatePosition(TimeSpan position)
|
public void UpdatePosition(TimeSpan position)
|
||||||
{
|
{
|
||||||
if (position < TimeSpan.Zero)
|
if (position < TimeSpan.Zero)
|
||||||
BaseLayerPropertyKeyframe.Position = TimeSpan.Zero;
|
LayerPropertyKeyframe.Position = TimeSpan.Zero;
|
||||||
else if (position > _profileEditorService.SelectedProfileElement.TimelineLength)
|
else if (position > _profileEditorService.SelectedProfileElement.TimelineLength)
|
||||||
BaseLayerPropertyKeyframe.Position = _profileEditorService.SelectedProfileElement.TimelineLength;
|
LayerPropertyKeyframe.Position = _profileEditorService.SelectedProfileElement.TimelineLength;
|
||||||
else
|
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
|
#endregion
|
||||||
|
|||||||
@ -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();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -9,12 +9,11 @@
|
|||||||
xmlns:timeline="clr-namespace:Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline"
|
xmlns:timeline="clr-namespace:Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800"
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
d:DataContext="{d:DesignInstance local:TimelinePropertyViewModel}"
|
|
||||||
Visibility="{Binding LayerPropertyBaseViewModel.IsVisible, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"
|
Visibility="{Binding LayerPropertyBaseViewModel.IsVisible, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"
|
||||||
MinWidth="{Binding Width}"
|
MinWidth="{Binding Width}"
|
||||||
HorizontalAlignment="Stretch">
|
HorizontalAlignment="Stretch">
|
||||||
<Border Height="25" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource MaterialDesignDivider}">
|
<Border Height="25" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource MaterialDesignDivider}">
|
||||||
<ItemsControl ItemsSource="{Binding TimelineKeyframeViewModels}"
|
<ItemsControl ItemsSource="{Binding Items}"
|
||||||
Background="{DynamicResource MaterialDesignToolBarBackground}"
|
Background="{DynamicResource MaterialDesignToolBarBackground}"
|
||||||
HorizontalAlignment="Left">
|
HorizontalAlignment="Left">
|
||||||
<ItemsControl.ItemsPanel>
|
<ItemsControl.ItemsPanel>
|
||||||
|
|||||||
@ -1,108 +1,61 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Abstract;
|
using Artemis.Core;
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using Stylet;
|
using Stylet;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
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;
|
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;
|
_profileEditorService = profileEditorService;
|
||||||
LayerPropertyViewModel = (LayerPropertyViewModel<T>) layerPropertyBaseViewModel;
|
|
||||||
|
|
||||||
LayerPropertyViewModel.LayerProperty.KeyframeAdded += LayerPropertyOnKeyframeModified;
|
LayerProperty = layerProperty;
|
||||||
LayerPropertyViewModel.LayerProperty.KeyframeRemoved += LayerPropertyOnKeyframeModified;
|
LayerPropertyViewModel = layerPropertyViewModel;
|
||||||
LayerPropertyViewModel.LayerProperty.KeyframesToggled += LayerPropertyOnKeyframeModified;
|
|
||||||
_profileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
// Only show keyframes if they are enabled
|
||||||
if (LayerPropertyViewModel.LayerProperty.KeyframesEnabled)
|
if (LayerProperty.KeyframesEnabled)
|
||||||
{
|
{
|
||||||
var keyframes = LayerPropertyViewModel.LayerProperty.Keyframes.ToList();
|
var keyframes = LayerProperty.Keyframes.ToList();
|
||||||
var toRemove = TimelineKeyframeViewModels.Where(t => !keyframes.Contains(t.BaseLayerPropertyKeyframe)).ToList();
|
var toRemove = Items.Where(t => !keyframes.Contains(t.LayerPropertyKeyframe)).ToList();
|
||||||
foreach (var timelineKeyframeViewModel in toRemove)
|
foreach (var timelineKeyframeViewModel in toRemove)
|
||||||
timelineKeyframeViewModel.Dispose();
|
timelineKeyframeViewModel.Dispose();
|
||||||
|
|
||||||
TimelineKeyframeViewModels.RemoveRange(toRemove);
|
Items.RemoveRange(toRemove);
|
||||||
TimelineKeyframeViewModels.AddRange(keyframes
|
Items.AddRange(keyframes
|
||||||
.Where(k => TimelineKeyframeViewModels.All(t => t.BaseLayerPropertyKeyframe != k))
|
.Where(k => Items.All(t => t.LayerPropertyKeyframe != k))
|
||||||
.Select(k => new TimelineKeyframeViewModel<T>(_profileEditorService, k))
|
.Select(k => new TimelineKeyframeViewModel<T>(k, _profileEditorService))
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
DisposeKeyframeViewModels();
|
Items.Clear();
|
||||||
|
|
||||||
foreach (var timelineKeyframeViewModel in TimelineKeyframeViewModels)
|
foreach (var timelineKeyframeViewModel in Items)
|
||||||
timelineKeyframeViewModel.Update(_profileEditorService.PixelsPerSecond);
|
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()
|
public interface ITimelinePropertyViewModel : IScreen, IDisposable
|
||||||
{
|
{
|
||||||
foreach (var timelineKeyframeViewModel in TimelineKeyframeViewModels)
|
List<TimeSpan> GetAllKeyframePositions();
|
||||||
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
|
|
||||||
{
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -8,7 +8,6 @@ using System.Windows.Input;
|
|||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Shapes;
|
using System.Windows.Shapes;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Abstract;
|
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using Stylet;
|
using Stylet;
|
||||||
@ -32,8 +31,6 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
|||||||
|
|
||||||
SelectedProfileElement.PropertyChanged += SelectedProfileElementOnPropertyChanged;
|
SelectedProfileElement.PropertyChanged += SelectedProfileElementOnPropertyChanged;
|
||||||
_profileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
|
_profileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||||
|
|
||||||
Update();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public RenderProfileElement SelectedProfileElement { get; set; }
|
public RenderProfileElement SelectedProfileElement { get; set; }
|
||||||
@ -63,20 +60,6 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
|
|||||||
SelectedProfileElement.PropertyChanged -= SelectedProfileElementOnPropertyChanged;
|
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)
|
private void SelectedProfileElementOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
if (e.PropertyName == nameof(_profileEditorService.SelectedProfileElement.StartSegmentLength))
|
if (e.PropertyName == nameof(_profileEditorService.SelectedProfileElement.StartSegmentLength))
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree.TreePropertyGroupView"
|
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree.TreeGroupView"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
@ -9,7 +9,7 @@
|
|||||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||||
xmlns:dd="urn:gong-wpf-dragdrop"
|
xmlns:dd="urn:gong-wpf-dragdrop"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DataContext="{d:DesignInstance local:LayerPropertyGroupTreeViewModel}"
|
d:DataContext="{d:DesignInstance local:TreeGroupViewModel}"
|
||||||
d:DesignHeight="450" d:DesignWidth="800">
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
<converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||||
@ -14,14 +14,14 @@ using Stylet;
|
|||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
||||||
{
|
{
|
||||||
public class LayerPropertyGroupTreeViewModel : PropertyChangedBase
|
public class TreeGroupViewModel : PropertyChangedBase
|
||||||
{
|
{
|
||||||
private readonly IDialogService _dialogService;
|
private readonly IDialogService _dialogService;
|
||||||
private readonly IKernel _kernel;
|
private readonly IKernel _kernel;
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private readonly IWindowManager _windowManager;
|
private readonly IWindowManager _windowManager;
|
||||||
|
|
||||||
public LayerPropertyGroupTreeViewModel(
|
public TreeGroupViewModel(
|
||||||
LayerPropertyGroupViewModel layerPropertyGroupViewModel,
|
LayerPropertyGroupViewModel layerPropertyGroupViewModel,
|
||||||
IProfileEditorService profileEditorService,
|
IProfileEditorService profileEditorService,
|
||||||
IDialogService dialogService,
|
IDialogService dialogService,
|
||||||
@ -1,4 +1,4 @@
|
|||||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree.LayerPropertyTreeView"
|
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree.TreePropertyView"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
@ -7,12 +7,12 @@ using Stylet;
|
|||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
||||||
{
|
{
|
||||||
public class LayerPropertyTreeViewModel<T> : Screen, ILayerPropertyTreeViewModel
|
public class TreePropertyViewModel<T> : Screen, ITreePropertyViewModel
|
||||||
{
|
{
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private PropertyInputViewModel<T> _propertyInputViewModel;
|
private PropertyInputViewModel<T> _propertyInputViewModel;
|
||||||
|
|
||||||
public LayerPropertyTreeViewModel(LayerProperty<T> layerProperty, LayerPropertyViewModel layerPropertyViewModel, IProfileEditorService profileEditorService)
|
public TreePropertyViewModel(LayerProperty<T> layerProperty, LayerPropertyViewModel layerPropertyViewModel, IProfileEditorService profileEditorService)
|
||||||
{
|
{
|
||||||
_profileEditorService = profileEditorService;
|
_profileEditorService = profileEditorService;
|
||||||
LayerProperty = layerProperty;
|
LayerProperty = layerProperty;
|
||||||
@ -86,7 +86,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
|||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ILayerPropertyTreeViewModel : IScreen, IDisposable
|
public interface ITreePropertyViewModel : IScreen, IDisposable
|
||||||
{
|
{
|
||||||
bool HasPropertyInputViewModel { get; }
|
bool HasPropertyInputViewModel { get; }
|
||||||
}
|
}
|
||||||
@ -99,10 +99,10 @@
|
|||||||
</TreeView.ItemContainerStyle>
|
</TreeView.ItemContainerStyle>
|
||||||
<TreeView.Resources>
|
<TreeView.Resources>
|
||||||
<HierarchicalDataTemplate DataType="{x:Type local:LayerPropertyGroupViewModel}" ItemsSource="{Binding Items}">
|
<HierarchicalDataTemplate DataType="{x:Type local:LayerPropertyGroupViewModel}" ItemsSource="{Binding Items}">
|
||||||
<ContentControl s:View.Model="{Binding LayerPropertyGroupTreeViewModel}" />
|
<ContentControl s:View.Model="{Binding TreeGroupViewModel}" />
|
||||||
</HierarchicalDataTemplate>
|
</HierarchicalDataTemplate>
|
||||||
<DataTemplate DataType="{x:Type local:LayerPropertyViewModel}">
|
<DataTemplate DataType="{x:Type local:LayerPropertyViewModel}">
|
||||||
<ContentControl s:View.Model="{Binding LayerPropertyTreeViewModel}" dd:DragDrop.DragSourceIgnore="True" />
|
<ContentControl s:View.Model="{Binding TreePropertyViewModel}" dd:DragDrop.DragSourceIgnore="True" />
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</TreeView.Resources>
|
</TreeView.Resources>
|
||||||
</TreeView>
|
</TreeView>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user