UI - Further restructuring

This commit is contained in:
SpoinkyNL committed 2020-05-14 21:58:30 +02:00
1 parent a9c9d06354
commit 678fad95d1
53 files changed
+459 -1242

No files matched your search

@@ -1,55 +0,0 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline.PropertyTimelineView"
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:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline"
xmlns:s="https://github.com/canton7/Stylet"
mc:Ignorable="d"
d:DesignHeight="25"
d:DesignWidth="800"
d:DataContext="{d:DesignInstance local:PropertyTimelineViewModel}">
<Grid Background="{DynamicResource MaterialDesignToolBarBackground}"
MouseDown="{s:Action TimelineCanvasMouseDown}"
MouseUp="{s:Action TimelineCanvasMouseUp}"
MouseMove="{s:Action TimelineCanvasMouseMove}">
<Grid.Triggers>
<EventTrigger RoutedEvent="UIElement.MouseLeftButtonDown">
<BeginStoryboard>
<Storyboard Storyboard.TargetName="MultiSelectionPath" Storyboard.TargetProperty="Opacity">
<DoubleAnimation From="0" To="1" Duration="0:0:0.1" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="UIElement.MouseLeftButtonUp">
<BeginStoryboard>
<Storyboard Storyboard.TargetName="MultiSelectionPath" Storyboard.TargetProperty="Opacity">
<DoubleAnimation From="1" To="0" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Grid.Triggers>
<ItemsControl ItemsSource="{Binding PropertyTrackViewModels}"
Width="{Binding Width}"
MinWidth="{Binding ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ScrollViewer}}"
HorizontalAlignment="Left">
<ItemsControl.ItemTemplate>
<DataTemplate>
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
<!-- Multi-selection rectangle -->
<Path Data="{Binding SelectionRectangle}" Opacity="0"
Stroke="{DynamicResource PrimaryHueLightBrush}"
StrokeThickness="1"
x:Name="MultiSelectionPath"
IsHitTestVisible="False">
<Path.Fill>
<SolidColorBrush Color="{DynamicResource Primary400}" Opacity="0.25" />
</Path.Fill>
</Path>
</Grid>
</UserControl>
@@ -1,245 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using Artemis.UI.Events;
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Services.Interfaces;
using Artemis.UI.Shared.Utilities;
using Artemis.UI.Utilities;
using Stylet;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
{
public class PropertyTimelineViewModel : PropertyChangedBase, IDisposable
{
private readonly IProfileEditorService _profileEditorService;
private readonly IPropertyTrackVmFactory _propertyTrackVmFactory;
public PropertyTimelineViewModel(LayerPropertiesViewModel layerPropertiesViewModel,
IProfileEditorService profileEditorService,
IPropertyTrackVmFactory propertyTrackVmFactory)
{
_profileEditorService = profileEditorService;
_propertyTrackVmFactory = propertyTrackVmFactory;
LayerPropertiesViewModel = layerPropertiesViewModel;
PropertyTrackViewModels = new BindableCollection<PropertyTrackViewModel>();
_profileEditorService.SelectedProfileElementUpdated += OnSelectedProfileElementUpdated;
LayerPropertiesViewModel.PixelsPerSecondChanged += OnPixelsPerSecondChanged;
Execute.PostToUIThread(() => SelectionRectangle = new RectangleGeometry());
}
public LayerPropertiesViewModel LayerPropertiesViewModel { get; }
public double Width { get; set; }
public BindableCollection<PropertyTrackViewModel> PropertyTrackViewModels { get; set; }
public RectangleGeometry SelectionRectangle { get; set; }
public void Dispose()
{
_profileEditorService.SelectedProfileElementUpdated -= OnSelectedProfileElementUpdated;
LayerPropertiesViewModel.PixelsPerSecondChanged -= OnPixelsPerSecondChanged;
}
public void UpdateEndTime()
{
// End time is the last keyframe + 10 sec
var lastKeyFrame = PropertyTrackViewModels.SelectMany(r => r.KeyframeViewModels).OrderByDescending(t => t.Keyframe.Position).FirstOrDefault();
var endTime = lastKeyFrame?.Keyframe.Position.Add(new TimeSpan(0, 0, 0, 10)) ?? TimeSpan.FromSeconds(10);
Width = endTime.TotalSeconds * LayerPropertiesViewModel.PixelsPerSecond;
// Ensure the caret isn't outside the end time
if (_profileEditorService.CurrentTime > endTime)
_profileEditorService.CurrentTime = endTime;
}
public void PopulateProperties(List<LayerPropertyViewModel> properties)
{
var newViewModels = new List<PropertyTrackViewModel>();
foreach (var property in properties)
newViewModels.AddRange(CreateViewModels(property));
PropertyTrackViewModels.Clear();
PropertyTrackViewModels.AddRange(newViewModels);
UpdateEndTime();
}
public void AddLayerProperty(LayerPropertyViewModel layerPropertyViewModel)
{
// Determine the index by flattening all the layer's properties
var index = layerPropertyViewModel.LayerProperty.GetFlattenedIndex();
if (index > PropertyTrackViewModels.Count)
index = PropertyTrackViewModels.Count;
PropertyTrackViewModels.Insert(index, _propertyTrackVmFactory.Create(this, layerPropertyViewModel));
}
public void RemoveLayerProperty(LayerPropertyViewModel layerPropertyViewModel)
{
var vm = PropertyTrackViewModels.FirstOrDefault(v => v.LayerPropertyViewModel == layerPropertyViewModel);
if (vm != null)
PropertyTrackViewModels.Remove(vm);
}
public void UpdateKeyframePositions()
{
foreach (var viewModel in PropertyTrackViewModels)
viewModel.UpdateKeyframes(LayerPropertiesViewModel.PixelsPerSecond);
UpdateEndTime();
}
/// <summary>
/// Updates the time line's keyframes
/// </summary>
public void Update()
{
foreach (var viewModel in PropertyTrackViewModels)
viewModel.PopulateKeyframes();
UpdateEndTime();
}
private void OnSelectedProfileElementUpdated(object sender, ProfileElementEventArgs e)
{
Update();
}
private void OnPixelsPerSecondChanged(object sender, EventArgs e)
{
UpdateKeyframePositions();
}
private List<PropertyTrackViewModel> CreateViewModels(LayerPropertyViewModel property)
{
var result = new List<PropertyTrackViewModel> {_propertyTrackVmFactory.Create(this, property)};
foreach (var child in property.Children)
result.AddRange(CreateViewModels(child));
return result;
}
#region Keyframe movement
public void MoveSelectedKeyframes(TimeSpan cursorTime)
{
// Ensure the selection rectangle doesn't show, the view isn't aware of different types of dragging
SelectionRectangle.Rect = new Rect();
var keyframeViewModels = PropertyTrackViewModels.SelectMany(t => t.KeyframeViewModels.OrderBy(k => k.Keyframe.Position)).ToList();
foreach (var keyframeViewModel in keyframeViewModels.Where(k => k.IsSelected))
keyframeViewModel.ApplyMovement(cursorTime);
_profileEditorService.UpdateProfilePreview();
}
public void ReleaseSelectedKeyframes()
{
var keyframeViewModels = PropertyTrackViewModels.SelectMany(t => t.KeyframeViewModels.OrderBy(k => k.Keyframe.Position)).ToList();
foreach (var keyframeViewModel in keyframeViewModels.Where(k => k.IsSelected))
keyframeViewModel.ReleaseMovement();
}
#endregion
#region Keyframe selection
private Point _mouseDragStartPoint;
private bool _mouseDragging;
// ReSharper disable once UnusedMember.Global - Called from view
public void TimelineCanvasMouseDown(object sender, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Released)
return;
((IInputElement) sender).CaptureMouse();
SelectionRectangle.Rect = new Rect();
_mouseDragStartPoint = e.GetPosition((IInputElement) sender);
_mouseDragging = true;
e.Handled = true;
}
// ReSharper disable once UnusedMember.Global - Called from view
public void TimelineCanvasMouseUp(object sender, MouseEventArgs e)
{
if (!_mouseDragging)
return;
var position = e.GetPosition((IInputElement) sender);
var selectedRect = new Rect(_mouseDragStartPoint, position);
SelectionRectangle.Rect = selectedRect;
var selectedKeyframes = HitTestUtilities.GetHitViewModels<PropertyTrackKeyframeViewModel>((Visual) sender, SelectionRectangle);
var keyframeViewModels = PropertyTrackViewModels.SelectMany(t => t.KeyframeViewModels.OrderBy(k => k.Keyframe.Position)).ToList();
foreach (var keyframeViewModel in keyframeViewModels)
keyframeViewModel.IsSelected = selectedKeyframes.Contains(keyframeViewModel);
_mouseDragging = false;
e.Handled = true;
((IInputElement) sender).ReleaseMouseCapture();
}
public void TimelineCanvasMouseMove(object sender, MouseEventArgs e)
{
if (_mouseDragging && e.LeftButton == MouseButtonState.Pressed)
{
var position = e.GetPosition((IInputElement) sender);
var selectedRect = new Rect(_mouseDragStartPoint, position);
SelectionRectangle.Rect = selectedRect;
e.Handled = true;
}
}
public void SelectKeyframe(PropertyTrackKeyframeViewModel clicked, bool selectBetween, bool toggle)
{
var keyframeViewModels = PropertyTrackViewModels.SelectMany(t => t.KeyframeViewModels.OrderBy(k => k.Keyframe.Position)).ToList();
if (selectBetween)
{
var selectedIndex = keyframeViewModels.FindIndex(k => k.IsSelected);
// If nothing is selected, select only the clicked
if (selectedIndex == -1)
{
clicked.IsSelected = true;
return;
}
foreach (var keyframeViewModel in keyframeViewModels)
keyframeViewModel.IsSelected = false;
var clickedIndex = keyframeViewModels.IndexOf(clicked);
if (clickedIndex < selectedIndex)
{
foreach (var keyframeViewModel in keyframeViewModels.Skip(clickedIndex).Take(selectedIndex - clickedIndex + 1))
keyframeViewModel.IsSelected = true;
}
else
{
foreach (var keyframeViewModel in keyframeViewModels.Skip(selectedIndex).Take(clickedIndex - selectedIndex + 1))
keyframeViewModel.IsSelected = true;
}
}
else if (toggle)
{
// Toggle only the clicked keyframe, leave others alone
clicked.IsSelected = !clicked.IsSelected;
}
else
{
// Only select the clicked keyframe
foreach (var keyframeViewModel in keyframeViewModels)
keyframeViewModel.IsSelected = false;
clicked.IsSelected = true;
}
}
#endregion
}
}
@@ -1,51 +0,0 @@
using System.Windows;
using System.Windows.Media;
using Artemis.Core.Utilities;
using Humanizer;
using Stylet;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
{
public class PropertyTrackEasingViewModel : PropertyChangedBase
{
private readonly PropertyTrackKeyframeViewModel _keyframeViewModel;
private bool _isEasingModeSelected;
public PropertyTrackEasingViewModel(PropertyTrackKeyframeViewModel keyframeViewModel, Easings.Functions easingFunction)
{
_keyframeViewModel = keyframeViewModel;
_isEasingModeSelected = keyframeViewModel.Keyframe.EasingFunction == easingFunction;
EasingFunction = easingFunction;
Description = easingFunction.Humanize();
CreateGeometry();
}
public Easings.Functions EasingFunction { get; }
public PointCollection EasingPoints { get; set; }
public string Description { get; set; }
public bool IsEasingModeSelected
{
get => _isEasingModeSelected;
set
{
_isEasingModeSelected = value;
if (_isEasingModeSelected)
_keyframeViewModel.SelectEasingMode(this);
}
}
private void CreateGeometry()
{
EasingPoints = new PointCollection();
for (var i = 1; i <= 10; i++)
{
var x = i;
var y = Easings.Interpolate(i / 10.0, EasingFunction) * 10;
EasingPoints.Add(new Point(x, y));
}
}
}
}
@@ -1,176 +0,0 @@
using System;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using Artemis.Core.Models.Profile.LayerProperties;
using Artemis.Core.Utilities;
using Artemis.UI.Services.Interfaces;
using Stylet;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
{
public class PropertyTrackKeyframeViewModel<T> : PropertyTrackKeyframeViewModel
{
private readonly IProfileEditorService _profileEditorService;
private int _pixelsPerSecond;
public PropertyTrackKeyframeViewModel(PropertyTrackViewModel propertyTrackViewModel, LayerPropertyKeyframe<T> keyframe, IProfileEditorService profileEditorService)
{
_profileEditorService = profileEditorService;
PropertyTrackViewModel = propertyTrackViewModel;
Keyframe = keyframe;
EasingViewModels = new BindableCollection<PropertyTrackEasingViewModel>();
CreateEasingViewModels();
}
public bool IsSelected { get; set; }
public PropertyTrackViewModel PropertyTrackViewModel { get; }
public LayerPropertyKeyframe<T> Keyframe { get; }
public BindableCollection<PropertyTrackEasingViewModel> EasingViewModels { get; set; }
public double X { get; set; }
public string Timestamp { get; set; }
public UIElement ParentView { get; set; }
public void Update(int pixelsPerSecond)
{
_pixelsPerSecond = pixelsPerSecond;
X = pixelsPerSecond * Keyframe.Position.TotalSeconds;
Timestamp = $"{Math.Floor(Keyframe.Position.TotalSeconds):00}.{Keyframe.Position.Milliseconds:000}";
}
#region Keyframe movement
public void KeyframeMouseDown(object sender, MouseButtonEventArgs e)
{
if (e.LeftButton == MouseButtonState.Released)
return;
((IInputElement) sender).CaptureMouse();
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift) && !IsSelected)
PropertyTrackViewModel.PropertyTimelineViewModel.SelectKeyframe(this, true, false);
else if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
PropertyTrackViewModel.PropertyTimelineViewModel.SelectKeyframe(this, false, true);
else if (!IsSelected)
PropertyTrackViewModel.PropertyTimelineViewModel.SelectKeyframe(this, false, false);
e.Handled = true;
}
public void KeyframeMouseUp(object sender, MouseButtonEventArgs e)
{
_profileEditorService.UpdateSelectedProfileElement();
PropertyTrackViewModel.PropertyTimelineViewModel.ReleaseSelectedKeyframes();
((IInputElement) sender).ReleaseMouseCapture();
}
public void KeyframeMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
PropertyTrackViewModel.PropertyTimelineViewModel.MoveSelectedKeyframes(GetCursorTime(e.GetPosition(ParentView)));
e.Handled = true;
}
private TimeSpan GetCursorTime(Point position)
{
// Get the parent grid, need that for our position
var x = Math.Max(0, position.X);
var time = TimeSpan.FromSeconds(x / _pixelsPerSecond);
// Round the time to something that fits the current zoom level
if (_pixelsPerSecond < 200)
time = TimeSpan.FromMilliseconds(Math.Round(time.TotalMilliseconds / 5.0) * 5.0);
else if (_pixelsPerSecond < 500)
time = TimeSpan.FromMilliseconds(Math.Round(time.TotalMilliseconds / 2.0) * 2.0);
else
time = TimeSpan.FromMilliseconds(Math.Round(time.TotalMilliseconds));
// If shift is held, snap to the current time
// Take a tolerance of 5 pixels (half a keyframe width)
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
{
var tolerance = 1000f / _pixelsPerSecond * 5;
if (Math.Abs(_profileEditorService.CurrentTime.TotalMilliseconds - time.TotalMilliseconds) < tolerance)
time = _profileEditorService.CurrentTime;
}
return time;
}
#endregion
#region Context menu actions
public void Copy()
{
var keyframe = PropertyTrackViewModel.LayerPropertyViewModel.LayerProperty.CreateNewKeyframe(Keyframe.Position, Keyframe.BaseValue);
keyframe.EasingFunction = Keyframe.EasingFunction;
_profileEditorService.UpdateSelectedProfileElement();
}
public void Delete()
{
PropertyTrackViewModel.LayerPropertyViewModel.LayerProperty.RemoveKeyframe(Keyframe);
_profileEditorService.UpdateSelectedProfileElement();
}
#endregion
#region Easing
private void CreateEasingViewModels()
{
EasingViewModels.AddRange(Enum.GetValues(typeof(Easings.Functions)).Cast<Easings.Functions>().Select(v => new PropertyTrackEasingViewModel(this, v)));
}
public void SelectEasingMode(PropertyTrackEasingViewModel easingViewModel)
{
Keyframe.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();
}
#endregion
#region Movement
private bool _movementReleased = true;
private TimeSpan _startOffset;
public void ApplyMovement(TimeSpan cursorTime)
{
if (_movementReleased)
{
_movementReleased = false;
_startOffset = cursorTime - Keyframe.Position;
}
else
{
Keyframe.Position = cursorTime - _startOffset;
if (Keyframe.Position < TimeSpan.Zero)
Keyframe.Position = TimeSpan.Zero;
Update(_pixelsPerSecond);
}
}
public void ReleaseMovement()
{
_movementReleased = true;
}
#endregion
}
public abstract class PropertyTrackKeyframeViewModel : PropertyChangedBase
{
}
}
@@ -1,111 +0,0 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline.PropertyTrackView"
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:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:s="https://github.com/canton7/Stylet"
mc:Ignorable="d"
d:DesignHeight="20" d:DesignWidth="600"
d:DataContext="{d:DesignInstance local:PropertyTrackViewModel}">
<Border Height="25"
BorderThickness="0,0,0,1"
BorderBrush="{DynamicResource MaterialDesignDivider}"
Visibility="{Binding MustDisplay, Converter={StaticResource BoolToVisibilityConverter}}">
<ItemsControl ItemsSource="{Binding KeyframeViewModels}"
Background="{DynamicResource MaterialDesignToolBarBackground}"
HorizontalAlignment="Left">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="{x:Type ContentPresenter}">
<Setter Property="Canvas.Left" Value="{Binding X}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse Fill="{StaticResource PrimaryHueMidBrush}"
Stroke="White"
StrokeThickness="0"
Width="10"
Height="10"
Margin="-5,6,0,0"
ToolTip="{Binding Timestamp}"
s:View.ActionTarget="{Binding}"
MouseDown="{s:Action KeyframeMouseDown}"
MouseUp="{s:Action KeyframeMouseUp}"
MouseMove="{s:Action KeyframeMouseMove}">
<Ellipse.Style>
<Style TargetType="{x:Type Ellipse}">
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="StrokeThickness" To="1" Duration="0:0:0.25" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="StrokeThickness" To="0" Duration="0:0:0.25" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Ellipse.Style>
<Ellipse.ContextMenu>
<ContextMenu>
<MenuItem Header="Copy" Command="{s:Action Copy}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="ContentCopy" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Delete" Command="{s:Action Delete}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="Delete" />
</MenuItem.Icon>
</MenuItem>
<Separator />
<MenuItem Header="Easing" ItemsSource="{Binding EasingViewModels}">
<MenuItem.ItemContainerStyle>
<Style TargetType="{x:Type MenuItem}" BasedOn="{StaticResource MaterialDesignMenuItem}">
<Setter Property="IsCheckable" Value="True" />
<Setter Property="IsChecked" Value="{Binding Path=IsEasingModeSelected, Mode=TwoWay}" />
</Style>
</MenuItem.ItemContainerStyle>
<MenuItem.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Polyline Stroke="{DynamicResource MaterialDesignBody}"
StrokeThickness="1"
Points="{Binding EasingPoints}"
Stretch="Uniform"
Width="20"
Height="20"
Margin="0 0 10 0" />
<TextBlock Text="{Binding Description}" />
</StackPanel>
</DataTemplate>
</MenuItem.ItemTemplate>
</MenuItem>
<!-- <MenuItem Header="Easing mode" IsEnabled="{Binding CanSelectEasingMode}"> -->
<!-- <MenuItem Header="Ease in" Command="{s:Action SetEasingMode}" CommandParameter="EaseIn" /> -->
<!-- <MenuItem Header="Ease out" Command="{s:Action SetEasingMode}" CommandParameter="EaseOut" /> -->
<!-- <MenuItem Header="Ease in and out" Command="{s:Action SetEasingMode}" CommandParameter="EaseInOut" /> -->
<!-- </MenuItem> -->
</ContextMenu>
</Ellipse.ContextMenu>
</Ellipse>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Border>
</UserControl>
@@ -1,91 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Artemis.UI.Ninject.Factories;
using Stylet;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
{
public class PropertyTrackViewModel : Screen
{
private readonly IPropertyTrackKeyframeVmFactory _propertyTrackKeyframeVmFactory;
public PropertyTrackViewModel(PropertyTimelineViewModel propertyTimelineViewModel, LayerPropertyViewModel layerPropertyViewModel,
IPropertyTrackKeyframeVmFactory propertyTrackKeyframeVmFactory)
{
_propertyTrackKeyframeVmFactory = propertyTrackKeyframeVmFactory;
PropertyTimelineViewModel = propertyTimelineViewModel;
LayerPropertyViewModel = layerPropertyViewModel;
KeyframeViewModels = new BindableCollection<PropertyTrackKeyframeViewModel>();
PopulateKeyframes();
UpdateKeyframes(PropertyTimelineViewModel.LayerPropertiesViewModel.PixelsPerSecond);
LayerPropertyViewModel.ExpandedStateChanged += (sender, args) => UpdateMustDisplay();
LayerPropertyViewModel.LayerProperty.VisibilityChanged += (sender, args) => UpdateMustDisplay();
UpdateMustDisplay();
}
public PropertyTimelineViewModel PropertyTimelineViewModel { get; }
public LayerPropertyViewModel LayerPropertyViewModel { get; }
public BindableCollection<PropertyTrackKeyframeViewModel> KeyframeViewModels { get; set; }
public bool MustDisplay { get; set; }
private void UpdateMustDisplay()
{
var expandedTest = LayerPropertyViewModel.Parent;
while (expandedTest != null)
{
if (!expandedTest.IsExpanded)
{
MustDisplay = false;
return;
}
expandedTest = expandedTest.Parent;
}
var visibilityTest = LayerPropertyViewModel.LayerProperty;
while (visibilityTest != null)
{
if (visibilityTest.IsHidden)
{
MustDisplay = false;
return;
}
visibilityTest = visibilityTest.Parent;
}
MustDisplay = true;
}
public void PopulateKeyframes()
{
// Remove old keyframes
KeyframeViewModels.RemoveRange(KeyframeViewModels.ToList().Where(vm => !LayerPropertyViewModel.LayerProperty.UntypedKeyframes.Contains(vm.Keyframe)));
// Add new keyframes
KeyframeViewModels.AddRange(
LayerPropertyViewModel.LayerProperty.UntypedKeyframes
.Where(k => KeyframeViewModels.All(vm => vm.Keyframe != k))
.Select(k => _propertyTrackKeyframeVmFactory.Create(this, k))
);
UpdateKeyframes(PropertyTimelineViewModel.LayerPropertiesViewModel.PixelsPerSecond);
}
public void UpdateKeyframes(int pixelsPerSecond)
{
foreach (var keyframeViewModel in KeyframeViewModels)
{
keyframeViewModel.ParentView = View;
keyframeViewModel.Update(pixelsPerSecond);
}
}
protected override void OnViewLoaded()
{
foreach (var keyframeViewModel in KeyframeViewModels)
keyframeViewModel.ParentView = View;
base.OnViewLoaded();
}
}
}
@@ -0,0 +1,14 @@
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Abstract;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
{
public class TimelinePropertyGroupViewModel
{
public TimelinePropertyGroupViewModel(LayerPropertyBaseViewModel layerPropertyBaseViewModel)
{
LayerPropertyGroupViewModel = (LayerPropertyGroupViewModel) layerPropertyBaseViewModel;
}
public LayerPropertyGroupViewModel LayerPropertyGroupViewModel { get; }
}
}
@@ -0,0 +1,30 @@
using System;
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Abstract;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
{
public class TimelinePropertyViewModel<T> : TimelinePropertyViewModel
{
public TimelinePropertyViewModel(LayerPropertyBaseViewModel layerPropertyBaseViewModel) : base(layerPropertyBaseViewModel)
{
LayerPropertyViewModel = (LayerPropertyViewModel<T>) layerPropertyBaseViewModel;
}
public LayerPropertyViewModel<T> LayerPropertyViewModel { get; }
public override void Dispose()
{
}
}
public abstract class TimelinePropertyViewModel : IDisposable
{
protected TimelinePropertyViewModel(LayerPropertyBaseViewModel layerPropertyBaseViewModel)
{
LayerPropertyBaseViewModel = layerPropertyBaseViewModel;
}
public LayerPropertyBaseViewModel LayerPropertyBaseViewModel { get; }
public abstract void Dispose();
}
}
@@ -0,0 +1,14 @@
using Stylet;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
{
public class TimelineViewModel
{
public TimelineViewModel(BindableCollection<LayerPropertyGroupViewModel> layerPropertyGroups)
{
LayerPropertyGroups = layerPropertyGroups;
}
public BindableCollection<LayerPropertyGroupViewModel> LayerPropertyGroups { get; }
}
}