using System; using System.Collections.Generic; using System.Linq; using System.Reflection; using Artemis.Core; using Artemis.UI.Ninject.Factories; using Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline; using Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree; using Artemis.UI.Shared.Services; using Stylet; namespace Artemis.UI.Screens.ProfileEditor.LayerProperties { public sealed class LayerPropertyGroupViewModel : Conductor.Collection.AllActive { private readonly IProfileEditorService _profileEditorService; private readonly ILayerPropertyVmFactory _layerPropertyVmFactory; private bool _isVisible; private TreeGroupViewModel _treeGroupViewModel; private TimelineGroupViewModel _timelineGroupViewModel; private bool _hasChildren; public LayerPropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, IProfileEditorService profileEditorService, ILayerPropertyVmFactory layerPropertyVmFactory) { _profileEditorService = profileEditorService; _layerPropertyVmFactory = layerPropertyVmFactory; LayerPropertyGroup = layerPropertyGroup; IsVisible = !LayerPropertyGroup.IsHidden; TreeGroupViewModel = _layerPropertyVmFactory.TreeGroupViewModel(this); TreeGroupViewModel.ConductWith(this); TimelineGroupViewModel = _layerPropertyVmFactory.TimelineGroupViewModel(this); TimelineGroupViewModel.ConductWith(this); } public LayerPropertyGroup LayerPropertyGroup { get; } public TreeGroupViewModel TreeGroupViewModel { get => _treeGroupViewModel; set => SetAndNotify(ref _treeGroupViewModel, value); } public TimelineGroupViewModel TimelineGroupViewModel { get => _timelineGroupViewModel; set => SetAndNotify(ref _timelineGroupViewModel, value); } public bool IsVisible { get => _isVisible; set => SetAndNotify(ref _isVisible, value); } public bool IsExpanded { get => LayerPropertyGroup.ProfileElement.IsPropertyGroupExpanded(LayerPropertyGroup); set { LayerPropertyGroup.ProfileElement.SetPropertyGroupExpanded(LayerPropertyGroup, value); NotifyOfPropertyChange(nameof(IsExpanded)); } } public bool HasChildren { get => _hasChildren; set => SetAndNotify(ref _hasChildren, value); } protected override void OnInitialActivate() { LayerPropertyGroup.VisibilityChanged += LayerPropertyGroupOnVisibilityChanged; PopulateChildren(); base.OnInitialActivate(); } protected override void OnClose() { LayerPropertyGroup.VisibilityChanged -= LayerPropertyGroupOnVisibilityChanged; base.OnClose(); } public void UpdateOrder(int order) { if (LayerPropertyGroup.LayerEffect != null) LayerPropertyGroup.LayerEffect.Order = order; NotifyOfPropertyChange(nameof(IsExpanded)); } public List GetAllKeyframeViewModels(bool expandedOnly) { List result = new(); if (expandedOnly && !IsExpanded) return result; foreach (Screen child in Items) { if (child is LayerPropertyViewModel layerPropertyViewModel) result.AddRange(layerPropertyViewModel.TimelinePropertyViewModel.GetAllKeyframeViewModels()); else if (child is LayerPropertyGroupViewModel layerPropertyGroupViewModel) result.AddRange(layerPropertyGroupViewModel.GetAllKeyframeViewModels(expandedOnly)); } return result; } /// /// Removes the keyframes between the and position from this property /// group /// /// The position at which to start removing keyframes, if null this will start at the first keyframe /// The position at which to start removing keyframes, if null this will end at the last keyframe public void WipeKeyframes(TimeSpan? start, TimeSpan? end) { foreach (Screen item in Items) { if (item is LayerPropertyViewModel layerPropertyViewModel) layerPropertyViewModel.TimelinePropertyViewModel.WipeKeyframes(start, end); else if (item is LayerPropertyGroupViewModel layerPropertyGroupViewModel) layerPropertyGroupViewModel.WipeKeyframes(start, end); } TimelineGroupViewModel.UpdateKeyframePositions(); } /// /// Shifts the keyframes between the and position by the provided /// /// /// The position at which to start shifting keyframes, if null this will start at the first keyframe /// The position at which to start shifting keyframes, if null this will end at the last keyframe /// The amount to shift the keyframes for public void ShiftKeyframes(TimeSpan? start, TimeSpan? end, TimeSpan amount) { foreach (Screen item in Items) { if (item is LayerPropertyViewModel layerPropertyViewModel) layerPropertyViewModel.TimelinePropertyViewModel.ShiftKeyframes(start, end, amount); else if (item is LayerPropertyGroupViewModel layerPropertyGroupViewModel) layerPropertyGroupViewModel.ShiftKeyframes(start, end, amount); } TimelineGroupViewModel.UpdateKeyframePositions(); } private void LayerPropertyGroupOnVisibilityChanged(object sender, EventArgs e) { IsVisible = !LayerPropertyGroup.IsHidden; } private void PopulateChildren() { // Get all properties and property groups and create VMs for them // The group has methods for getting this without reflection but then we lose the order of the properties as they are defined on the group foreach (PropertyInfo propertyInfo in LayerPropertyGroup.GetType().GetProperties()) { if (Attribute.IsDefined(propertyInfo, typeof(LayerPropertyIgnoreAttribute))) continue; if (typeof(ILayerProperty).IsAssignableFrom(propertyInfo.PropertyType)) { ILayerProperty value = (ILayerProperty) propertyInfo.GetValue(LayerPropertyGroup); // Ensure a supported input VM was found, otherwise don't add it if (value != null && _profileEditorService.CanCreatePropertyInputViewModel(value)) Items.Add(_layerPropertyVmFactory.LayerPropertyViewModel(value)); } else if (typeof(LayerPropertyGroup).IsAssignableFrom(propertyInfo.PropertyType)) { LayerPropertyGroup value = (LayerPropertyGroup) propertyInfo.GetValue(LayerPropertyGroup); if (value != null) Items.Add(_layerPropertyVmFactory.LayerPropertyGroupViewModel(value)); } } HasChildren = Items.Any(i => i is LayerPropertyViewModel {IsVisible: true} || i is LayerPropertyGroupViewModel {IsVisible: true}); } } }