diff --git a/src/Artemis.UI/Ninject/Factories/IVMFactory.cs b/src/Artemis.UI/Ninject/Factories/IVMFactory.cs index 04c3cecef..86b82e29e 100644 --- a/src/Artemis.UI/Ninject/Factories/IVMFactory.cs +++ b/src/Artemis.UI/Ninject/Factories/IVMFactory.cs @@ -80,8 +80,9 @@ namespace Artemis.UI.Ninject.Factories { LayerPropertyViewModel LayerPropertyViewModel(ILayerProperty layerProperty); LayerPropertyGroupViewModel LayerPropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup); - LayerPropertyTreeViewModel LayerPropertyGroupViewModel(LayerProperty layerProperty); - LayerPropertyGroupTreeViewModel LayerPropertyGroupTreeViewModel(LayerPropertyGroupViewModel layerPropertyGroupViewModel); + TreePropertyViewModel LayerPropertyGroupViewModel(LayerProperty layerProperty); + TreeGroupViewModel TreeGroupViewModel(LayerPropertyGroupViewModel layerPropertyGroupViewModel); + TimelineGroupViewModel TimelineGroupViewModel(LayerPropertyGroupViewModel layerPropertyGroupViewModel); LayerPropertyGroupViewModel LayerPropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, PropertyGroupDescriptionAttribute propertyGroupDescription); TreeViewModel TreeViewModel(LayerPropertiesViewModel layerPropertiesViewModel, BindableCollection layerPropertyGroups); EffectsViewModel EffectsViewModel(LayerPropertiesViewModel layerPropertiesViewModel); diff --git a/src/Artemis.UI/Ninject/InstanceProviders/DataBindingsViewModelInstanceProvider.cs b/src/Artemis.UI/Ninject/InstanceProviders/DataBindingsViewModelInstanceProvider.cs new file mode 100644 index 000000000..5df778f89 --- /dev/null +++ b/src/Artemis.UI/Ninject/InstanceProviders/DataBindingsViewModelInstanceProvider.cs @@ -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); + } + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs index dd0743d08..e3a6c0974 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs @@ -16,7 +16,7 @@ using Artemis.UI.Shared; using Artemis.UI.Shared.Services; using GongSolutions.Wpf.DragDrop; 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 { @@ -246,7 +246,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties { RightSideIndex = 1; DataBindingsViewModel?.Dispose(); - DataBindingsViewModel = _dataBindingsVmFactory.DataBindingsViewModel(ProfileEditorService.SelectedDataBinding); + // TODO + // DataBindingsViewModel = _dataBindingsVmFactory.DataBindingsViewModel(ProfileEditorService.SelectedDataBinding); } else RightSideIndex = 0; @@ -357,7 +358,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties } SortProperties(); - UpdateKeyframes(); + TimelineViewModel.Update(); } private void ApplyEffects() @@ -392,18 +393,18 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties } SortProperties(); - UpdateKeyframes(); + TimelineViewModel.Update(); } private void SortProperties() { // Get all non-effect properties var nonEffectProperties = LayerPropertyGroups - .Where(l => l.LayerPropertyGroupTreeViewModel.GroupType != LayerEffectRoot) + .Where(l => l.TreeGroupViewModel.GroupType != LayerEffectRoot) .ToList(); // Order the effects var effectProperties = LayerPropertyGroups - .Where(l => l.LayerPropertyGroupTreeViewModel.GroupType == LayerEffectRoot) + .Where(l => l.TreeGroupViewModel.GroupType == LayerEffectRoot) .OrderBy(l => l.LayerPropertyGroup.LayerEffect.Order) .ToList(); @@ -421,12 +422,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties LayerPropertyGroups.Move(LayerPropertyGroups.IndexOf(layerPropertyGroupViewModel), index + nonEffectProperties.Count); } } - - private void UpdateKeyframes() - { - TimelineViewModel.Update(); - } - + #endregion #region Drag and drop @@ -442,8 +438,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties var target = dropInfo.TargetItem as LayerPropertyGroupViewModel; if (source == target || - target?.LayerPropertyGroupTreeViewModel.GroupType != LayerEffectRoot || - source?.LayerPropertyGroupTreeViewModel.GroupType != LayerEffectRoot) + target?.TreeGroupViewModel.GroupType != LayerEffectRoot || + source?.TreeGroupViewModel.GroupType != LayerEffectRoot) return; dropInfo.DropTargetAdorner = DropTargetAdorners.Insert; @@ -461,8 +457,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties var target = dropInfo.TargetItem as LayerPropertyGroupViewModel; if (source == target || - target?.LayerPropertyGroupTreeViewModel.GroupType != LayerEffectRoot || - source?.LayerPropertyGroupTreeViewModel.GroupType != LayerEffectRoot) + target?.TreeGroupViewModel.GroupType != LayerEffectRoot || + source?.TreeGroupViewModel.GroupType != LayerEffectRoot) return; if (dropInfo.InsertPosition == RelativeInsertPosition.BeforeTargetItem) @@ -491,7 +487,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties private void ApplyCurrentEffectsOrder() { 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); order++; diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertyGroupViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertyGroupViewModel.cs index ae3e7091a..09f4e5132 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertyGroupViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertyGroupViewModel.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using Artemis.Core; using Artemis.UI.Ninject.Factories; +using Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline; using Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree; using Stylet; @@ -16,13 +17,17 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties _layerPropertyVmFactory = layerPropertyVmFactory; LayerPropertyGroup = layerPropertyGroup; - LayerPropertyGroupTreeViewModel = layerPropertyVmFactory.LayerPropertyGroupTreeViewModel(this); + Children = new BindableCollection(); + + TreeGroupViewModel = layerPropertyVmFactory.TreeGroupViewModel(this); + TimelineGroupViewModel = layerPropertyVmFactory.TimelineGroupViewModel(this); PopulateChildren(); } public LayerPropertyGroup LayerPropertyGroup { get; } - public LayerPropertyGroupTreeViewModel LayerPropertyGroupTreeViewModel { get; } - public BindableCollection Children { get; set; } + public TreeGroupViewModel TreeGroupViewModel { get; } + public TimelineGroupViewModel TimelineGroupViewModel { get; } + public BindableCollection Children { get; } public bool IsVisible => !LayerPropertyGroup.IsHidden; @@ -51,7 +56,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties { var layerPropertyViewModel = _layerPropertyVmFactory.LayerPropertyViewModel(layerProperty); // After creation ensure a supported input VM was found, if not, discard the VM - if (!layerPropertyViewModel.LayerPropertyTreeViewModel.HasPropertyInputViewModel) + if (!layerPropertyViewModel.TreePropertyViewModel.HasPropertyInputViewModel) layerPropertyViewModel.Dispose(); else Children.Add(layerPropertyViewModel); @@ -86,7 +91,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties foreach (var child in Children) { if (child is LayerPropertyViewModel layerPropertyViewModel) - result.AddRange(layerPropertyViewModel.LayerPropertyTimelineViewModel.GetAllKeyframePositions()); + result.AddRange(layerPropertyViewModel.TimelinePropertyViewModel.GetAllKeyframePositions()); else if (child is LayerPropertyGroupViewModel layerPropertyGroupViewModel) result.AddRange(layerPropertyGroupViewModel.GetAllKeyframePositions(expandedOnly)); } diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertyViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertyViewModel.cs index f436b7f0d..50eb8cdcd 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertyViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/LayerPropertyViewModel.cs @@ -1,5 +1,6 @@ using System; using Artemis.Core; +using Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline; using Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree; using Ninject; using Ninject.Parameters; @@ -14,24 +15,24 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties LayerProperty = layerProperty; var parameter = new ConstructorArgument("layerProperty", LayerProperty); - var treeViewModelType = typeof(LayerPropertyTreeViewModel<>).MakeGenericType(layerProperty.GetType().GetGenericArguments()); - var timelineViewModelType = typeof(LayerPropertyTimelineViewModel<>).MakeGenericType(layerProperty.GetType().GetGenericArguments()); + var treeViewModelType = typeof(TreePropertyViewModel<>).MakeGenericType(layerProperty.GetType().GetGenericArguments()); + var timelineViewModelType = typeof(TimelinePropertyViewModel<>).MakeGenericType(layerProperty.GetType().GetGenericArguments()); - LayerPropertyTreeViewModel = (ILayerPropertyTreeViewModel) kernel.Get(treeViewModelType, parameter); - LayerPropertyTimelineViewModel = (ILayerPropertyTimelineViewModel) kernel.Get(timelineViewModelType, parameter); + TreePropertyViewModel = (ITreePropertyViewModel) kernel.Get(treeViewModelType, parameter); + TimelinePropertyViewModel = (ITimelinePropertyViewModel) kernel.Get(timelineViewModelType, parameter); } public ILayerProperty LayerProperty { get; } - public ILayerPropertyTreeViewModel LayerPropertyTreeViewModel { get; } - public ILayerPropertyTimelineViewModel LayerPropertyTimelineViewModel { get; } + public ITreePropertyViewModel TreePropertyViewModel { get; } + public ITimelinePropertyViewModel TimelinePropertyViewModel { get; } public bool IsVisible { get; set; } public bool IsExpanded { get; set; } public void Dispose() { - LayerPropertyTreeViewModel?.Dispose(); - LayerPropertyTimelineViewModel?.Dispose(); + TreePropertyViewModel?.Dispose(); + TimelinePropertyViewModel?.Dispose(); } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/Rails/LayerPropertyTimelineViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/Rails/LayerPropertyTimelineViewModel.cs deleted file mode 100644 index 36a6e00c8..000000000 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/Rails/LayerPropertyTimelineViewModel.cs +++ /dev/null @@ -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 : Screen, ILayerPropertyTimelineViewModel - { - public LayerProperty LayerProperty { get; } - public LayerPropertyViewModel LayerPropertyViewModel { get; } - - public LayerPropertyTimelineViewModel(LayerProperty layerProperty, LayerPropertyViewModel layerPropertyViewModel) - { - LayerProperty = layerProperty; - LayerPropertyViewModel = layerPropertyViewModel; - } - - public List GetAllKeyframePositions() - { - return LayerProperty.Keyframes.Select(k => k.Position).ToList(); - } - - public void Dispose() - { - } - } - - public interface ILayerPropertyTimelineViewModel : IScreen, IDisposable - { - List GetAllKeyframePositions(); - } -} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/Rails/TimelineGroupViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/Rails/TimelineGroupViewModel.cs deleted file mode 100644 index fb39a056f..000000000 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/Rails/TimelineGroupViewModel.cs +++ /dev/null @@ -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; - } - } -} diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineEasingViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineEasingViewModel.cs index a89e161cb..859643892 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineEasingViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineEasingViewModel.cs @@ -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); + } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyGroupView.xaml b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineGroupView.xaml similarity index 82% rename from src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyGroupView.xaml rename to src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineGroupView.xaml index 96852f448..0715f4cb5 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyGroupView.xaml +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineGroupView.xaml @@ -1,14 +1,14 @@ - @@ -20,7 +20,7 @@ @@ -59,14 +59,13 @@ - - + + - - + + - - \ No newline at end of file + diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineGroupViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineGroupViewModel.cs new file mode 100644 index 000000000..9e40b1bb8 --- /dev/null +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineGroupViewModel.cs @@ -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(); + + _profileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged; + UpdateKeyframePositions(); + } + + public LayerPropertyGroupViewModel LayerPropertyGroupViewModel { get; } + public LayerPropertyGroup LayerPropertyGroup { get; } + + public BindableCollection 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)); + } + } +} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineKeyframeViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineKeyframeViewModel.cs index 34210bdae..c586ce613 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineKeyframeViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineKeyframeViewModel.cs @@ -7,73 +7,23 @@ using Stylet; namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline { - public class TimelineKeyframeViewModel : TimelineKeyframeViewModel + public class TimelineKeyframeViewModel : Screen, IDisposable { private readonly IProfileEditorService _profileEditorService; - public TimelineKeyframeViewModel(IProfileEditorService profileEditorService, LayerPropertyKeyframe layerPropertyKeyframe) - : base(profileEditorService, layerPropertyKeyframe) - { - _profileEditorService = profileEditorService; - LayerPropertyKeyframe = layerPropertyKeyframe; - } - - public LayerPropertyKeyframe LayerPropertyKeyframe { get; } - - #region Context menu actions - - public override void Copy() - { - var newKeyframe = new LayerPropertyKeyframe( - 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 _easingViewModels; private bool _isSelected; - private int _pixelsPerSecond; private string _timestamp; private double _x; - protected TimelineKeyframeViewModel(IProfileEditorService profileEditorService, BaseLayerPropertyKeyframe baseLayerPropertyKeyframe) + public TimelineKeyframeViewModel(LayerPropertyKeyframe layerPropertyKeyframe, IProfileEditorService profileEditorService) { _profileEditorService = profileEditorService; - BaseLayerPropertyKeyframe = baseLayerPropertyKeyframe; - EasingViewModels = new BindableCollection(); - - BaseLayerPropertyKeyframe.PropertyChanged += BaseLayerPropertyKeyframeOnPropertyChanged; + LayerPropertyKeyframe = layerPropertyKeyframe; + LayerPropertyKeyframe.PropertyChanged += LayerPropertyKeyframeOnPropertyChanged; } - public BaseLayerPropertyKeyframe BaseLayerPropertyKeyframe { get; } + public LayerPropertyKeyframe LayerPropertyKeyframe { get; } public BindableCollection 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().Select(v => new TimelineEasingViewModel(this, v))); + if (EasingViewModels.Any()) + return; + + EasingViewModels.AddRange(Enum.GetValues(typeof(Easings.Functions)) + .Cast() + .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 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 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( + 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 diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyGroupViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyGroupViewModel.cs deleted file mode 100644 index ea05a499d..000000000 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyGroupViewModel.cs +++ /dev/null @@ -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 _timelineKeyframeViewModels; - - public TimelinePropertyGroupViewModel(LayerPropertyBaseViewModel layerPropertyBaseViewModel, IProfileEditorService profileEditorService) - { - _profileEditorService = profileEditorService; - LayerPropertyGroupViewModel = (LayerPropertyGroupViewModel) layerPropertyBaseViewModel; - TimelineKeyframeViewModels = new BindableCollection(); - - LayerPropertyGroupViewModel.ProfileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged; - LayerPropertyGroupViewModel.PropertyChanged += LayerPropertyGroupViewModelOnPropertyChanged; - UpdateKeyframes(); - } - - public LayerPropertyGroupViewModel LayerPropertyGroupViewModel { get; } - - public BindableCollection 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(); - } - } -} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyView.xaml b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyView.xaml index 5fcb44d45..6438ce3e8 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyView.xaml +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyView.xaml @@ -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"> - diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyViewModel.cs index 53c0a6c5a..320bf9099 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelinePropertyViewModel.cs @@ -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 : TimelinePropertyViewModel + public class TimelinePropertyViewModel : Conductor>.Collection.AllActive, ITimelinePropertyViewModel { private readonly IProfileEditorService _profileEditorService; + public LayerProperty LayerProperty { get; } + public LayerPropertyViewModel LayerPropertyViewModel { get; } - public TimelinePropertyViewModel(LayerPropertyBaseViewModel layerPropertyBaseViewModel, IProfileEditorService profileEditorService) : base(layerPropertyBaseViewModel) + public TimelinePropertyViewModel(LayerProperty layerProperty, LayerPropertyViewModel layerPropertyViewModel, IProfileEditorService profileEditorService) { _profileEditorService = profileEditorService; - LayerPropertyViewModel = (LayerPropertyViewModel) layerPropertyBaseViewModel; - LayerPropertyViewModel.LayerProperty.KeyframeAdded += LayerPropertyOnKeyframeModified; - LayerPropertyViewModel.LayerProperty.KeyframeRemoved += LayerPropertyOnKeyframeModified; - LayerPropertyViewModel.LayerProperty.KeyframesToggled += LayerPropertyOnKeyframeModified; - _profileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged; + LayerProperty = layerProperty; + LayerPropertyViewModel = layerPropertyViewModel; } - public LayerPropertyViewModel LayerPropertyViewModel { get; } + public List 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(_profileEditorService, k)) + Items.RemoveRange(toRemove); + Items.AddRange(keyframes + .Where(k => Items.All(t => t.LayerPropertyKeyframe != k)) + .Select(k => new TimelineKeyframeViewModel(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 _timelineKeyframeViewModels; - private double _width; - - protected TimelinePropertyViewModel(LayerPropertyBaseViewModel layerPropertyBaseViewModel) - { - LayerPropertyBaseViewModel = layerPropertyBaseViewModel; - TimelineKeyframeViewModels = new BindableCollection(); - } - - public LayerPropertyBaseViewModel LayerPropertyBaseViewModel { get; } - - public BindableCollection 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 GetAllKeyframePositions(); } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineViewModel.cs index 133f0289f..263167481 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Timeline/TimelineViewModel.cs @@ -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)) diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/LayerPropertyGroupTreeView.xaml b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/TreeGroupView.xaml similarity index 98% rename from src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/LayerPropertyGroupTreeView.xaml rename to src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/TreeGroupView.xaml index a33638fbd..a8bcb0f63 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/LayerPropertyGroupTreeView.xaml +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/TreeGroupView.xaml @@ -1,4 +1,4 @@ - diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/LayerPropertyGroupTreeViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/TreeGroupViewModel.cs similarity index 98% rename from src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/LayerPropertyGroupTreeViewModel.cs rename to src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/TreeGroupViewModel.cs index 1b4be1dfd..57f27bd6e 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/LayerPropertyGroupTreeViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/TreeGroupViewModel.cs @@ -14,14 +14,14 @@ using Stylet; namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree { - public class LayerPropertyGroupTreeViewModel : PropertyChangedBase + public class TreeGroupViewModel : PropertyChangedBase { private readonly IDialogService _dialogService; private readonly IKernel _kernel; private readonly IProfileEditorService _profileEditorService; private readonly IWindowManager _windowManager; - public LayerPropertyGroupTreeViewModel( + public TreeGroupViewModel( LayerPropertyGroupViewModel layerPropertyGroupViewModel, IProfileEditorService profileEditorService, IDialogService dialogService, diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/LayerPropertyTreeView.xaml b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/TreePropertyView.xaml similarity index 98% rename from src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/LayerPropertyTreeView.xaml rename to src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/TreePropertyView.xaml index f31147e5d..ff231f5e0 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/LayerPropertyTreeView.xaml +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/TreePropertyView.xaml @@ -1,4 +1,4 @@ - : Screen, ILayerPropertyTreeViewModel + public class TreePropertyViewModel : Screen, ITreePropertyViewModel { private readonly IProfileEditorService _profileEditorService; private PropertyInputViewModel _propertyInputViewModel; - public LayerPropertyTreeViewModel(LayerProperty layerProperty, LayerPropertyViewModel layerPropertyViewModel, IProfileEditorService profileEditorService) + public TreePropertyViewModel(LayerProperty layerProperty, LayerPropertyViewModel layerPropertyViewModel, IProfileEditorService profileEditorService) { _profileEditorService = profileEditorService; LayerProperty = layerProperty; @@ -86,7 +86,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree #endregion } - public interface ILayerPropertyTreeViewModel : IScreen, IDisposable + public interface ITreePropertyViewModel : IScreen, IDisposable { bool HasPropertyInputViewModel { get; } } diff --git a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/TreeView.xaml b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/TreeView.xaml index 49e945658..66ec6e3ac 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/TreeView.xaml +++ b/src/Artemis.UI/Screens/ProfileEditor/LayerProperties/Tree/TreeView.xaml @@ -99,10 +99,10 @@ - + - +