1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Profile editor - Refactored a lot of VMs so they clean up nicely

This commit is contained in:
SpoinkyNL 2020-12-20 18:13:56 +01:00
parent 0dac4c7387
commit 4db66e1e3e
37 changed files with 532 additions and 497 deletions

View File

@ -288,13 +288,10 @@ namespace Artemis.Core
if (LayerBrush?.BaseProperties?.PropertiesInitialized == false || LayerBrush?.BrushType != LayerBrushType.Regular) if (LayerBrush?.BaseProperties?.PropertiesInitialized == false || LayerBrush?.BrushType != LayerBrushType.Regular)
return; return;
lock (Timeline) RenderTimeline(Timeline, canvas);
{ foreach (Timeline extraTimeline in Timeline.ExtraTimelines.ToList())
RenderTimeline(Timeline, canvas); RenderTimeline(extraTimeline, canvas);
foreach (Timeline extraTimeline in Timeline.ExtraTimelines) Timeline.ClearDelta();
RenderTimeline(extraTimeline, canvas);
Timeline.ClearDelta();
}
} }
private void ApplyTimeline(Timeline timeline) private void ApplyTimeline(Timeline timeline)
@ -384,6 +381,7 @@ namespace Artemis.Core
{ {
// ignored // ignored
} }
Renderer.Close(); Renderer.Close();
} }
} }

View File

@ -26,7 +26,12 @@ namespace Artemis.Core
/// <summary> /// <summary>
/// Gets the unique path of the property on the layer /// Gets the unique path of the property on the layer
/// </summary> /// </summary>
public string Path { get; } string Path { get; }
/// <summary>
/// Gets the type of the property
/// </summary>
Type PropertyType { get; }
/// <summary> /// <summary>
/// Initializes the layer property /// Initializes the layer property

View File

@ -39,20 +39,15 @@ namespace Artemis.Core
_keyframes = new List<LayerPropertyKeyframe<T>>(); _keyframes = new List<LayerPropertyKeyframe<T>>();
} }
/// <summary>
/// Returns the type of the property
/// </summary>
public Type GetPropertyType()
{
return typeof(T);
}
/// <inheritdoc /> /// <inheritdoc />
public PropertyDescriptionAttribute PropertyDescription { get; internal set; } public PropertyDescriptionAttribute PropertyDescription { get; internal set; }
/// <inheritdoc /> /// <inheritdoc />
public string Path { get; private set; } public string Path { get; private set; }
/// <inheritdoc />
public Type PropertyType => typeof(T);
/// <inheritdoc /> /// <inheritdoc />
public void Update(Timeline timeline) public void Update(Timeline timeline)
{ {

View File

@ -15,7 +15,7 @@
<Rectangle.OpacityMask> <Rectangle.OpacityMask>
<VisualBrush Stretch="Uniform"> <VisualBrush Stretch="Uniform">
<VisualBrush.Visual> <VisualBrush.Visual>
<svgc:SvgViewbox Source="{Binding}" Name="SvgDisplay"/> <Image Source="{Binding Converter={svgc:SvgImageConverter}, Mode=OneWay}"/>
</VisualBrush.Visual> </VisualBrush.Visual>
</VisualBrush> </VisualBrush>
</Rectangle.OpacityMask> </Rectangle.OpacityMask>

View File

@ -13,7 +13,8 @@ namespace Artemis.UI.Shared
public abstract class PropertyInputViewModel<T> : PropertyInputViewModel public abstract class PropertyInputViewModel<T> : PropertyInputViewModel
{ {
private bool _inputDragging; private bool _inputDragging;
[AllowNull] private T _inputValue = default!; [AllowNull]
private T _inputValue = default!;
/// <summary> /// <summary>
/// Creates a new instance of the <see cref="PropertyInputViewModel" /> class /// Creates a new instance of the <see cref="PropertyInputViewModel" /> class
@ -24,11 +25,6 @@ namespace Artemis.UI.Shared
{ {
LayerProperty = layerProperty; LayerProperty = layerProperty;
ProfileEditorService = profileEditorService; ProfileEditorService = profileEditorService;
LayerProperty.Updated += LayerPropertyOnUpdated;
LayerProperty.CurrentValueSet += LayerPropertyOnUpdated;
LayerProperty.DataBindingEnabled += LayerPropertyOnDataBindingChange;
LayerProperty.DataBindingDisabled += LayerPropertyOnDataBindingChange;
UpdateInputValue();
} }
/// <summary> /// <summary>
@ -41,11 +37,6 @@ namespace Artemis.UI.Shared
{ {
LayerProperty = layerProperty; LayerProperty = layerProperty;
ProfileEditorService = profileEditorService; ProfileEditorService = profileEditorService;
LayerProperty.Updated += LayerPropertyOnUpdated;
LayerProperty.CurrentValueSet += LayerPropertyOnUpdated;
LayerProperty.DataBindingEnabled += LayerPropertyOnDataBindingChange;
LayerProperty.DataBindingDisabled += LayerPropertyOnDataBindingChange;
UpdateInputValue();
} }
/// <summary> /// <summary>
@ -87,20 +78,27 @@ namespace Artemis.UI.Shared
internal override object InternalGuard { get; } = new(); internal override object InternalGuard { get; } = new();
#region IDisposable #region Overrides of Screen
/// <inheritdoc /> /// <inheritdoc />
protected override void Dispose(bool disposing) protected override void OnInitialActivate()
{ {
if (disposing) LayerProperty.Updated += LayerPropertyOnUpdated;
{ LayerProperty.CurrentValueSet += LayerPropertyOnUpdated;
LayerProperty.Updated -= LayerPropertyOnUpdated; LayerProperty.DataBindingEnabled += LayerPropertyOnDataBindingChange;
LayerProperty.CurrentValueSet -= LayerPropertyOnUpdated; LayerProperty.DataBindingDisabled += LayerPropertyOnDataBindingChange;
LayerProperty.DataBindingEnabled -= LayerPropertyOnDataBindingChange; UpdateInputValue();
LayerProperty.DataBindingDisabled -= LayerPropertyOnDataBindingChange; base.OnInitialActivate();
} }
base.Dispose(disposing); /// <inheritdoc />
protected override void OnClose()
{
LayerProperty.Updated -= LayerPropertyOnUpdated;
LayerProperty.CurrentValueSet -= LayerPropertyOnUpdated;
LayerProperty.DataBindingEnabled -= LayerPropertyOnDataBindingChange;
LayerProperty.DataBindingDisabled -= LayerPropertyOnDataBindingChange;
base.OnClose();
} }
#endregion #endregion
@ -207,7 +205,7 @@ namespace Artemis.UI.Shared
/// <summary> /// <summary>
/// For internal use only, implement <see cref="PropertyInputViewModel{T}" /> instead. /// For internal use only, implement <see cref="PropertyInputViewModel{T}" /> instead.
/// </summary> /// </summary>
public abstract class PropertyInputViewModel : ValidatingModelBase, IDisposable public abstract class PropertyInputViewModel : Screen
{ {
/// <summary> /// <summary>
/// For internal use only, implement <see cref="PropertyInputViewModel{T}" /> instead. /// For internal use only, implement <see cref="PropertyInputViewModel{T}" /> instead.
@ -228,30 +226,5 @@ namespace Artemis.UI.Shared
/// </summary> /// </summary>
// ReSharper disable once UnusedMember.Global // ReSharper disable once UnusedMember.Global
internal abstract object InternalGuard { get; } internal abstract object InternalGuard { get; }
#region IDisposable
/// <summary>
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
/// </summary>
/// <param name="disposing">
/// <see langword="true" /> to release both managed and unmanaged resources;
/// <see langword="false" /> to release only unmanaged resources.
/// </param>
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
}
}
/// <inheritdoc />
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
#endregion
} }
} }

View File

@ -1,6 +1,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Windows;
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Modules; using Artemis.Core.Modules;
@ -41,6 +42,11 @@ namespace Artemis.UI.Shared.Services
/// </summary> /// </summary>
ReadOnlyCollection<PropertyInputRegistration> RegisteredPropertyEditors { get; } ReadOnlyCollection<PropertyInputRegistration> RegisteredPropertyEditors { get; }
/// <summary>
/// Gets or sets a boolean indicating whether the editor is currently playing
/// </summary>
bool Playing { get; set; }
/// <summary> /// <summary>
/// Changes the selected profile /// Changes the selected profile
/// </summary> /// </summary>
@ -129,6 +135,12 @@ namespace Artemis.UI.Shared.Services
/// <returns></returns> /// <returns></returns>
TimeSpan SnapToTimeline(TimeSpan time, TimeSpan tolerance, bool snapToSegments, bool snapToCurrentTime, List<TimeSpan>? snapTimes = null); TimeSpan SnapToTimeline(TimeSpan time, TimeSpan tolerance, bool snapToSegments, bool snapToCurrentTime, List<TimeSpan>? snapTimes = null);
/// <summary>
/// Determines if there is a matching registration for the provided layer property
/// </summary>
/// <param name="layerProperty">The layer property to try to find a view model for</param>
bool CanCreatePropertyInputViewModel(ILayerProperty layerProperty);
/// <summary> /// <summary>
/// If a matching registration is found, creates a new <see cref="PropertyInputViewModel{T}" /> supporting /// If a matching registration is found, creates a new <see cref="PropertyInputViewModel{T}" /> supporting
/// <typeparamref name="T" /> /// <typeparamref name="T" />
@ -160,7 +172,13 @@ namespace Artemis.UI.Shared.Services
/// Gets a boolean indicating whether a profile element is on the clipboard /// Gets a boolean indicating whether a profile element is on the clipboard
/// </summary> /// </summary>
bool GetCanPasteProfileElement(); bool GetCanPasteProfileElement();
/// <summary>
/// Determines all LEDs on the current active surface contained in the specified rectangle
/// </summary>
/// <returns>A list containing all the LEDs that are in the provided rect</returns>
List<ArtemisLed> GetLedsInRectangle(Rect rect);
/// <summary> /// <summary>
/// Occurs when a new profile is selected /// Occurs when a new profile is selected
/// </summary> /// </summary>

View File

@ -2,6 +2,7 @@
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel; using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using System.Windows;
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Modules; using Artemis.Core.Modules;
using Artemis.Core.Services; using Artemis.Core.Services;
@ -11,6 +12,7 @@ using Newtonsoft.Json;
using Ninject; using Ninject;
using Ninject.Parameters; using Ninject.Parameters;
using Serilog; using Serilog;
using SkiaSharp.Views.WPF;
using Stylet; using Stylet;
namespace Artemis.UI.Shared.Services namespace Artemis.UI.Shared.Services
@ -71,6 +73,8 @@ namespace Artemis.UI.Shared.Services
} }
public ReadOnlyCollection<PropertyInputRegistration> RegisteredPropertyEditors => _registeredPropertyEditors.AsReadOnly(); public ReadOnlyCollection<PropertyInputRegistration> RegisteredPropertyEditors => _registeredPropertyEditors.AsReadOnly();
public bool Playing { get; set; }
public Profile? SelectedProfile { get; private set; } public Profile? SelectedProfile { get; private set; }
public RenderProfileElement? SelectedProfileElement { get; private set; } public RenderProfileElement? SelectedProfileElement { get; private set; }
public ILayerProperty? SelectedDataBinding { get; private set; } public ILayerProperty? SelectedDataBinding { get; private set; }
@ -302,6 +306,15 @@ namespace Artemis.UI.Shared.Services
return time; return time;
} }
public bool CanCreatePropertyInputViewModel(ILayerProperty layerProperty)
{
PropertyInputRegistration? registration = RegisteredPropertyEditors.FirstOrDefault(r => r.SupportedType == layerProperty.PropertyType);
if (registration == null && layerProperty.PropertyType.IsEnum)
registration = RegisteredPropertyEditors.FirstOrDefault(r => r.SupportedType == typeof(Enum));
return registration != null;
}
public PropertyInputViewModel<T>? CreatePropertyInputViewModel<T>(LayerProperty<T> layerProperty) public PropertyInputViewModel<T>? CreatePropertyInputViewModel<T>(LayerProperty<T> layerProperty)
{ {
Type? viewModelType = null; Type? viewModelType = null;
@ -339,6 +352,11 @@ namespace Artemis.UI.Shared.Services
return SelectedProfile?.Module; return SelectedProfile?.Module;
} }
public List<ArtemisLed> GetLedsInRectangle(Rect rect)
{
return _surfaceService.ActiveSurface.Devices.SelectMany(d => d.Leds).Where(led => led.AbsoluteRectangle.IntersectsWith(rect.ToSKRect())).ToList();
}
#region Copy/paste #region Copy/paste
public ProfileElement? DuplicateProfileElement(ProfileElement profileElement) public ProfileElement? DuplicateProfileElement(ProfileElement profileElement)

View File

@ -14,14 +14,10 @@ namespace Artemis.UI.PropertyInput
private readonly IPluginManagementService _pluginManagementService; private readonly IPluginManagementService _pluginManagementService;
private BindableCollection<LayerBrushDescriptor> _descriptors; private BindableCollection<LayerBrushDescriptor> _descriptors;
public BrushPropertyInputViewModel(LayerProperty<LayerBrushReference> layerProperty, public BrushPropertyInputViewModel(LayerProperty<LayerBrushReference> layerProperty, IProfileEditorService profileEditorService, IPluginManagementService pluginManagementService)
IProfileEditorService profileEditorService, : base(layerProperty, profileEditorService)
IPluginManagementService pluginManagementService) : base(layerProperty, profileEditorService)
{ {
_pluginManagementService = pluginManagementService; _pluginManagementService = pluginManagementService;
_pluginManagementService.PluginEnabled += PluginManagementServiceOnPluginManagementLoaded;
_pluginManagementService.PluginDisabled += PluginManagementServiceOnPluginManagementLoaded;
UpdateEnumValues(); UpdateEnumValues();
} }
@ -60,18 +56,22 @@ namespace Artemis.UI.PropertyInput
UpdateEnumValues(); UpdateEnumValues();
} }
#region IDisposable #region Overrides of Screen
/// <inheritdoc /> /// <inheritdoc />
protected override void Dispose(bool disposing) protected override void OnInitialActivate()
{ {
if (disposing) _pluginManagementService.PluginEnabled += PluginManagementServiceOnPluginManagementLoaded;
{ _pluginManagementService.PluginDisabled += PluginManagementServiceOnPluginManagementLoaded;
_pluginManagementService.PluginEnabled -= PluginManagementServiceOnPluginManagementLoaded; base.OnInitialActivate();
_pluginManagementService.PluginDisabled -= PluginManagementServiceOnPluginManagementLoaded; }
}
base.Dispose(disposing); /// <inheritdoc />
protected override void OnClose()
{
_pluginManagementService.PluginEnabled -= PluginManagementServiceOnPluginManagementLoaded;
_pluginManagementService.PluginDisabled -= PluginManagementServiceOnPluginManagementLoaded;
base.OnClose();
} }
#endregion #endregion

View File

@ -17,6 +17,7 @@ using Artemis.UI.Screens.ProfileEditor.Visualization.Tools;
using Artemis.UI.Screens.Settings.Debug; using Artemis.UI.Screens.Settings.Debug;
using Artemis.UI.Screens.Settings.Tabs.Devices; using Artemis.UI.Screens.Settings.Tabs.Devices;
using Artemis.UI.Screens.Settings.Tabs.Plugins; using Artemis.UI.Screens.Settings.Tabs.Plugins;
using Artemis.UI.Screens.Shared;
using Stylet; using Stylet;
namespace Artemis.UI.Ninject.Factories namespace Artemis.UI.Ninject.Factories
@ -53,15 +54,15 @@ namespace Artemis.UI.Ninject.Factories
public interface IProfileLayerVmFactory : IVmFactory public interface IProfileLayerVmFactory : IVmFactory
{ {
ProfileLayerViewModel Create(Layer layer, ProfileViewModel profileViewModel); ProfileLayerViewModel Create(Layer layer, PanZoomViewModel panZoomViewModel);
} }
public interface IVisualizationToolVmFactory : IVmFactory public interface IVisualizationToolVmFactory : IVmFactory
{ {
ViewpointMoveToolViewModel ViewpointMoveToolViewModel(ProfileViewModel profileViewModel); ViewpointMoveToolViewModel ViewpointMoveToolViewModel(PanZoomViewModel panZoomViewModel);
EditToolViewModel EditToolViewModel(ProfileViewModel profileViewModel); EditToolViewModel EditToolViewModel(PanZoomViewModel panZoomViewModel);
SelectionToolViewModel SelectionToolViewModel(ProfileViewModel profileViewModel); SelectionToolViewModel SelectionToolViewModel(PanZoomViewModel panZoomViewModel);
SelectionRemoveToolViewModel SelectionRemoveToolViewModel(ProfileViewModel profileViewModel); SelectionRemoveToolViewModel SelectionRemoveToolViewModel(PanZoomViewModel panZoomViewModel);
} }
public interface IDataModelConditionsVmFactory : IVmFactory public interface IDataModelConditionsVmFactory : IVmFactory
@ -82,10 +83,10 @@ namespace Artemis.UI.Ninject.Factories
TreeGroupViewModel TreeGroupViewModel(LayerPropertyGroupViewModel layerPropertyGroupViewModel); TreeGroupViewModel TreeGroupViewModel(LayerPropertyGroupViewModel layerPropertyGroupViewModel);
TimelineGroupViewModel TimelineGroupViewModel(LayerPropertyGroupViewModel layerPropertyGroupViewModel); TimelineGroupViewModel TimelineGroupViewModel(LayerPropertyGroupViewModel layerPropertyGroupViewModel);
TreeViewModel TreeViewModel(LayerPropertiesViewModel layerPropertiesViewModel, BindableCollection<LayerPropertyGroupViewModel> layerPropertyGroups); TreeViewModel TreeViewModel(LayerPropertiesViewModel layerPropertiesViewModel, IObservableCollection<LayerPropertyGroupViewModel> layerPropertyGroups);
EffectsViewModel EffectsViewModel(LayerPropertiesViewModel layerPropertiesViewModel); EffectsViewModel EffectsViewModel(LayerPropertiesViewModel layerPropertiesViewModel);
TimelineViewModel TimelineViewModel(LayerPropertiesViewModel layerPropertiesViewModel, BindableCollection<LayerPropertyGroupViewModel> layerPropertyGroups); TimelineViewModel TimelineViewModel(LayerPropertiesViewModel layerPropertiesViewModel, IObservableCollection<LayerPropertyGroupViewModel> layerPropertyGroups);
TimelineSegmentViewModel TimelineSegmentViewModel(SegmentViewModelType segment, BindableCollection<LayerPropertyGroupViewModel> layerPropertyGroups); TimelineSegmentViewModel TimelineSegmentViewModel(SegmentViewModelType segment, IObservableCollection<LayerPropertyGroupViewModel> layerPropertyGroups);
} }
public interface IDataBindingsVmFactory public interface IDataBindingsVmFactory

View File

@ -17,9 +17,6 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
{ {
_profileEditorService = profileEditorService; _profileEditorService = profileEditorService;
_dataBindingsVmFactory = dataBindingsVmFactory; _dataBindingsVmFactory = dataBindingsVmFactory;
_profileEditorService.SelectedDataBindingChanged += ProfileEditorServiceOnSelectedDataBindingChanged;
CreateDataBindingViewModels();
} }
public int SelectedItemIndex public int SelectedItemIndex
@ -27,13 +24,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
get => _selectedItemIndex; get => _selectedItemIndex;
set => SetAndNotify(ref _selectedItemIndex, value); set => SetAndNotify(ref _selectedItemIndex, value);
} }
protected override void OnClose()
{
_profileEditorService.SelectedDataBindingChanged -= ProfileEditorServiceOnSelectedDataBindingChanged;
base.OnClose();
}
private void CreateDataBindingViewModels() private void CreateDataBindingViewModels()
{ {
Items.Clear(); Items.Clear();
@ -48,7 +39,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
// and creating the actual data bindings // and creating the actual data bindings
foreach (IDataBindingRegistration registration in registrations) foreach (IDataBindingRegistration registration in registrations)
Items.Add(_dataBindingsVmFactory.DataBindingViewModel(registration)); Items.Add(_dataBindingsVmFactory.DataBindingViewModel(registration));
SelectedItemIndex = 0; SelectedItemIndex = 0;
} }
@ -56,5 +47,23 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
{ {
CreateDataBindingViewModels(); CreateDataBindingViewModels();
} }
#region Overrides of Screen
/// <inheritdoc />
protected override void OnInitialActivate()
{
_profileEditorService.SelectedDataBindingChanged += ProfileEditorServiceOnSelectedDataBindingChanged;
CreateDataBindingViewModels();
base.OnInitialActivate();
}
protected override void OnClose()
{
_profileEditorService.SelectedDataBindingChanged -= ProfileEditorServiceOnSelectedDataBindingChanged;
base.OnClose();
}
#endregion
} }
} }

View File

@ -23,11 +23,10 @@ using MouseButtonEventArgs = System.Windows.Input.MouseButtonEventArgs;
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
{ {
public class LayerPropertiesViewModel : Conductor<IScreen>.Collection.AllActive, IProfileEditorPanelViewModel, IDropTarget public class LayerPropertiesViewModel : Conductor<LayerPropertyGroupViewModel>.Collection.AllActive, IProfileEditorPanelViewModel, IDropTarget
{ {
private readonly ILayerPropertyVmFactory _layerPropertyVmFactory; private readonly ILayerPropertyVmFactory _layerPropertyVmFactory;
private LayerPropertyGroupViewModel _brushPropertyGroup; private LayerPropertyGroupViewModel _brushPropertyGroup;
private bool _playing;
private bool _repeating; private bool _repeating;
private bool _repeatSegment; private bool _repeatSegment;
private bool _repeatTimeline = true; private bool _repeatTimeline = true;
@ -49,31 +48,27 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
CoreService = coreService; CoreService = coreService;
SettingsService = settingsService; SettingsService = settingsService;
LayerPropertyGroups = new BindableCollection<LayerPropertyGroupViewModel>();
PropertyChanged += HandlePropertyTreeIndexChanged; PropertyChanged += HandlePropertyTreeIndexChanged;
// Left side // Left side
TreeViewModel = _layerPropertyVmFactory.TreeViewModel(this, LayerPropertyGroups); TreeViewModel = _layerPropertyVmFactory.TreeViewModel(this, Items);
TreeViewModel.ConductWith(this);
EffectsViewModel = _layerPropertyVmFactory.EffectsViewModel(this); EffectsViewModel = _layerPropertyVmFactory.EffectsViewModel(this);
Items.Add(TreeViewModel); EffectsViewModel.ConductWith(this);
Items.Add(EffectsViewModel);
// Right side // Right side
StartTimelineSegmentViewModel = _layerPropertyVmFactory.TimelineSegmentViewModel(SegmentViewModelType.Start, LayerPropertyGroups); StartTimelineSegmentViewModel = _layerPropertyVmFactory.TimelineSegmentViewModel(SegmentViewModelType.Start, Items);
MainTimelineSegmentViewModel = _layerPropertyVmFactory.TimelineSegmentViewModel(SegmentViewModelType.Main, LayerPropertyGroups); StartTimelineSegmentViewModel.ConductWith(this);
EndTimelineSegmentViewModel = _layerPropertyVmFactory.TimelineSegmentViewModel(SegmentViewModelType.End, LayerPropertyGroups); MainTimelineSegmentViewModel = _layerPropertyVmFactory.TimelineSegmentViewModel(SegmentViewModelType.Main, Items);
TimelineViewModel = _layerPropertyVmFactory.TimelineViewModel(this, LayerPropertyGroups); MainTimelineSegmentViewModel.ConductWith(this);
EndTimelineSegmentViewModel = _layerPropertyVmFactory.TimelineSegmentViewModel(SegmentViewModelType.End, Items);
EndTimelineSegmentViewModel.ConductWith(this);
TimelineViewModel = _layerPropertyVmFactory.TimelineViewModel(this, Items);
TimelineViewModel.ConductWith(this);
DataBindingsViewModel = dataBindingsViewModel; DataBindingsViewModel = dataBindingsViewModel;
Items.Add(StartTimelineSegmentViewModel); DataBindingsViewModel.ConductWith(this);
Items.Add(MainTimelineSegmentViewModel);
Items.Add(EndTimelineSegmentViewModel);
Items.Add(TimelineViewModel);
Items.Add(DataBindingsViewModel);
} }
public BindableCollection<LayerPropertyGroupViewModel> LayerPropertyGroups { get; }
#region Child VMs #region Child VMs
public TreeViewModel TreeViewModel { get; } public TreeViewModel TreeViewModel { get; }
@ -92,8 +87,12 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
public bool Playing public bool Playing
{ {
get => _playing; get => ProfileEditorService.Playing;
set => SetAndNotify(ref _playing, value); set
{
ProfileEditorService.Playing = value;
NotifyOfPropertyChange(nameof(Playing));
}
} }
public bool Repeating public bool Repeating
@ -239,8 +238,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
public List<LayerPropertyGroupViewModel> GetAllLayerPropertyGroupViewModels() public List<LayerPropertyGroupViewModel> GetAllLayerPropertyGroupViewModels()
{ {
List<LayerPropertyGroupViewModel> groups = LayerPropertyGroups.ToList(); List<LayerPropertyGroupViewModel> groups = Items.ToList();
List<LayerPropertyGroupViewModel> toAdd = groups.SelectMany(g => g.Children).Where(g => g is LayerPropertyGroupViewModel).Cast<LayerPropertyGroupViewModel>().ToList(); List<LayerPropertyGroupViewModel> toAdd = groups.SelectMany(g => g.Items).Where(g => g is LayerPropertyGroupViewModel).Cast<LayerPropertyGroupViewModel>().ToList();
groups.AddRange(toAdd); groups.AddRange(toAdd);
return groups; return groups;
} }
@ -254,9 +253,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
SelectedLayer.LayerBrushUpdated -= SelectedLayerOnLayerBrushUpdated; SelectedLayer.LayerBrushUpdated -= SelectedLayerOnLayerBrushUpdated;
// Clear old properties // Clear old properties
foreach (LayerPropertyGroupViewModel layerPropertyGroupViewModel in LayerPropertyGroups) Items.Clear();
layerPropertyGroupViewModel.Dispose();
LayerPropertyGroups.Clear();
_brushPropertyGroup = null; _brushPropertyGroup = null;
if (profileElement == null) if (profileElement == null)
@ -271,8 +268,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
SelectedLayer.LayerBrushUpdated += SelectedLayerOnLayerBrushUpdated; SelectedLayer.LayerBrushUpdated += SelectedLayerOnLayerBrushUpdated;
// Add the built-in root groups of the layer // Add the built-in root groups of the layer
LayerPropertyGroups.Add(_layerPropertyVmFactory.LayerPropertyGroupViewModel(SelectedLayer.General)); Items.Add(_layerPropertyVmFactory.LayerPropertyGroupViewModel(SelectedLayer.General));
LayerPropertyGroups.Add(_layerPropertyVmFactory.LayerPropertyGroupViewModel(SelectedLayer.Transform)); Items.Add(_layerPropertyVmFactory.LayerPropertyGroupViewModel(SelectedLayer.Transform));
} }
ApplyLayerBrush(); ApplyLayerBrush();
@ -302,14 +299,14 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
if (_brushPropertyGroup != null) if (_brushPropertyGroup != null)
{ {
LayerPropertyGroups.Remove(_brushPropertyGroup); Items.Remove(_brushPropertyGroup);
_brushPropertyGroup = null; _brushPropertyGroup = null;
} }
if (SelectedLayer.LayerBrush != null) if (SelectedLayer.LayerBrush != null)
{ {
_brushPropertyGroup = _layerPropertyVmFactory.LayerPropertyGroupViewModel(SelectedLayer.LayerBrush.BaseProperties); _brushPropertyGroup = _layerPropertyVmFactory.LayerPropertyGroupViewModel(SelectedLayer.LayerBrush.BaseProperties);
LayerPropertyGroups.Add(_brushPropertyGroup); Items.Add(_brushPropertyGroup);
} }
SortProperties(); SortProperties();
@ -321,19 +318,19 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
return; return;
// Remove VMs of effects no longer applied on the layer // Remove VMs of effects no longer applied on the layer
List<LayerPropertyGroupViewModel> toRemove = LayerPropertyGroups List<LayerPropertyGroupViewModel> toRemove = Items
.Where(l => l.LayerPropertyGroup.LayerEffect != null && !SelectedProfileElement.LayerEffects.Contains(l.LayerPropertyGroup.LayerEffect)) .Where(l => l.LayerPropertyGroup.LayerEffect != null && !SelectedProfileElement.LayerEffects.Contains(l.LayerPropertyGroup.LayerEffect))
.ToList(); .ToList();
LayerPropertyGroups.RemoveRange(toRemove); Items.RemoveRange(toRemove);
foreach (LayerPropertyGroupViewModel layerPropertyGroupViewModel in toRemove) foreach (LayerPropertyGroupViewModel layerPropertyGroupViewModel in toRemove)
layerPropertyGroupViewModel.Dispose(); layerPropertyGroupViewModel.RequestClose();
foreach (BaseLayerEffect layerEffect in SelectedProfileElement.LayerEffects) foreach (BaseLayerEffect layerEffect in SelectedProfileElement.LayerEffects)
{ {
if (LayerPropertyGroups.Any(l => l.LayerPropertyGroup.LayerEffect == layerEffect) || layerEffect.BaseProperties == null) if (Items.Any(l => l.LayerPropertyGroup.LayerEffect == layerEffect) || layerEffect.BaseProperties == null)
continue; continue;
LayerPropertyGroups.Add(_layerPropertyVmFactory.LayerPropertyGroupViewModel(layerEffect.BaseProperties)); Items.Add(_layerPropertyVmFactory.LayerPropertyGroupViewModel(layerEffect.BaseProperties));
} }
SortProperties(); SortProperties();
@ -342,11 +339,11 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
private void SortProperties() private void SortProperties()
{ {
// Get all non-effect properties // Get all non-effect properties
List<LayerPropertyGroupViewModel> nonEffectProperties = LayerPropertyGroups List<LayerPropertyGroupViewModel> nonEffectProperties = Items
.Where(l => l.TreeGroupViewModel.GroupType != LayerEffectRoot) .Where(l => l.TreeGroupViewModel.GroupType != LayerEffectRoot)
.ToList(); .ToList();
// Order the effects // Order the effects
List<LayerPropertyGroupViewModel> effectProperties = LayerPropertyGroups List<LayerPropertyGroupViewModel> effectProperties = Items
.Where(l => l.TreeGroupViewModel.GroupType == LayerEffectRoot) .Where(l => l.TreeGroupViewModel.GroupType == LayerEffectRoot)
.OrderBy(l => l.LayerPropertyGroup.LayerEffect.Order) .OrderBy(l => l.LayerPropertyGroup.LayerEffect.Order)
.ToList(); .ToList();
@ -355,14 +352,14 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
for (int index = 0; index < nonEffectProperties.Count; index++) for (int index = 0; index < nonEffectProperties.Count; index++)
{ {
LayerPropertyGroupViewModel layerPropertyGroupViewModel = nonEffectProperties[index]; LayerPropertyGroupViewModel layerPropertyGroupViewModel = nonEffectProperties[index];
LayerPropertyGroups.Move(LayerPropertyGroups.IndexOf(layerPropertyGroupViewModel), index); ((BindableCollection<LayerPropertyGroupViewModel>) Items).Move(Items.IndexOf(layerPropertyGroupViewModel), index);
} }
// Put the effect properties after, sorted by their order // Put the effect properties after, sorted by their order
for (int index = 0; index < effectProperties.Count; index++) for (int index = 0; index < effectProperties.Count; index++)
{ {
LayerPropertyGroupViewModel layerPropertyGroupViewModel = effectProperties[index]; LayerPropertyGroupViewModel layerPropertyGroupViewModel = effectProperties[index];
LayerPropertyGroups.Move(LayerPropertyGroups.IndexOf(layerPropertyGroupViewModel), index + nonEffectProperties.Count); ((BindableCollection<LayerPropertyGroupViewModel>) Items).Move(Items.IndexOf(layerPropertyGroupViewModel), index + nonEffectProperties.Count);
} }
} }
@ -424,22 +421,22 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
private void MoveBefore(LayerPropertyGroupViewModel source, LayerPropertyGroupViewModel target) private void MoveBefore(LayerPropertyGroupViewModel source, LayerPropertyGroupViewModel target)
{ {
if (LayerPropertyGroups.IndexOf(target) == LayerPropertyGroups.IndexOf(source) + 1) if (Items.IndexOf(target) == Items.IndexOf(source) + 1)
return; return;
LayerPropertyGroups.Move(LayerPropertyGroups.IndexOf(source), LayerPropertyGroups.IndexOf(target)); ((BindableCollection<LayerPropertyGroupViewModel>) Items).Move(Items.IndexOf(source), Items.IndexOf(target));
} }
private void MoveAfter(LayerPropertyGroupViewModel source, LayerPropertyGroupViewModel target) private void MoveAfter(LayerPropertyGroupViewModel source, LayerPropertyGroupViewModel target)
{ {
LayerPropertyGroups.Remove(source); Items.Remove(source);
LayerPropertyGroups.Insert(LayerPropertyGroups.IndexOf(target) + 1, source); Items.Insert(Items.IndexOf(target) + 1, source);
} }
private void ApplyCurrentEffectsOrder() private void ApplyCurrentEffectsOrder()
{ {
int order = 1; int order = 1;
foreach (LayerPropertyGroupViewModel groupViewModel in LayerPropertyGroups.Where(p => p.TreeGroupViewModel.GroupType == LayerEffectRoot)) foreach (LayerPropertyGroupViewModel groupViewModel in Items.Where(p => p.TreeGroupViewModel.GroupType == LayerEffectRoot))
{ {
groupViewModel.UpdateOrder(order); groupViewModel.UpdateOrder(order);
order++; order++;
@ -530,7 +527,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
private TimeSpan CalculateEndTime() private TimeSpan CalculateEndTime()
{ {
List<ITimelineKeyframeViewModel> keyframeViewModels = LayerPropertyGroups.SelectMany(g => g.GetAllKeyframeViewModels(false)).ToList(); List<ITimelineKeyframeViewModel> keyframeViewModels = Items.SelectMany(g => g.GetAllKeyframeViewModels(false)).ToList();
// If there are no keyframes, don't stop at all // If there are no keyframes, don't stop at all
if (!keyframeViewModels.Any()) if (!keyframeViewModels.Any())
@ -627,7 +624,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
// If holding down shift, snap to the closest segment or keyframe // If holding down shift, snap to the closest segment or keyframe
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)) if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
{ {
List<TimeSpan> snapTimes = LayerPropertyGroups.SelectMany(g => g.GetAllKeyframeViewModels(true)).Select(k => k.Position).ToList(); List<TimeSpan> snapTimes = Items.SelectMany(g => g.GetAllKeyframeViewModels(true)).Select(k => k.Position).ToList();
TimeSpan snappedTime = ProfileEditorService.SnapToTimeline(newTime, TimeSpan.FromMilliseconds(1000f / ProfileEditorService.PixelsPerSecond * 5), true, false, snapTimes); TimeSpan snappedTime = ProfileEditorService.SnapToTimeline(newTime, TimeSpan.FromMilliseconds(1000f / ProfileEditorService.PixelsPerSecond * 5), true, false, snapTimes);
ProfileEditorService.CurrentTime = snappedTime; ProfileEditorService.CurrentTime = snappedTime;
return; return;

View File

@ -5,42 +5,53 @@ 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.Timeline;
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree; using Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree;
using Artemis.UI.Shared.Services;
using Stylet; using Stylet;
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
{ {
public sealed class LayerPropertyGroupViewModel : PropertyChangedBase, IDisposable public sealed class LayerPropertyGroupViewModel : Conductor<Screen>.Collection.AllActive
{ {
private readonly IProfileEditorService _profileEditorService;
private readonly ILayerPropertyVmFactory _layerPropertyVmFactory; private readonly ILayerPropertyVmFactory _layerPropertyVmFactory;
private bool _isVisible; private bool _isVisible;
private TreeGroupViewModel _treeGroupViewModel;
private TimelineGroupViewModel _timelineGroupViewModel;
public LayerPropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, ILayerPropertyVmFactory layerPropertyVmFactory) public LayerPropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, IProfileEditorService profileEditorService, ILayerPropertyVmFactory layerPropertyVmFactory)
{ {
_profileEditorService = profileEditorService;
_layerPropertyVmFactory = layerPropertyVmFactory; _layerPropertyVmFactory = layerPropertyVmFactory;
LayerPropertyGroup = layerPropertyGroup; LayerPropertyGroup = layerPropertyGroup;
Children = new BindableCollection<PropertyChangedBase>();
TreeGroupViewModel = layerPropertyVmFactory.TreeGroupViewModel(this);
TimelineGroupViewModel = layerPropertyVmFactory.TimelineGroupViewModel(this);
LayerPropertyGroup.VisibilityChanged += LayerPropertyGroupOnVisibilityChanged;
IsVisible = !LayerPropertyGroup.IsHidden; IsVisible = !LayerPropertyGroup.IsHidden;
PopulateChildren(); TreeGroupViewModel = _layerPropertyVmFactory.TreeGroupViewModel(this);
TreeGroupViewModel.ConductWith(this);
TimelineGroupViewModel = _layerPropertyVmFactory.TimelineGroupViewModel(this);
TimelineGroupViewModel.ConductWith(this);
} }
public LayerPropertyGroup LayerPropertyGroup { get; } public LayerPropertyGroup LayerPropertyGroup { get; }
public TreeGroupViewModel TreeGroupViewModel { get; }
public TimelineGroupViewModel TimelineGroupViewModel { get; } public TreeGroupViewModel TreeGroupViewModel
public BindableCollection<PropertyChangedBase> Children { get; } {
get => _treeGroupViewModel;
set => SetAndNotify(ref _treeGroupViewModel, value);
}
public TimelineGroupViewModel TimelineGroupViewModel
{
get => _timelineGroupViewModel;
set => SetAndNotify(ref _timelineGroupViewModel, value);
}
public bool IsVisible public bool IsVisible
{ {
get => _isVisible; get => _isVisible;
set => SetAndNotify(ref _isVisible, value); set => SetAndNotify(ref _isVisible, value);
} }
public bool IsExpanded public bool IsExpanded
{ {
get => LayerPropertyGroup.ProfileElement.IsPropertyGroupExpanded(LayerPropertyGroup); get => LayerPropertyGroup.ProfileElement.IsPropertyGroupExpanded(LayerPropertyGroup);
@ -51,25 +62,26 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
} }
} }
#region IDisposable
protected override void OnInitialActivate()
/// <inheritdoc />
public void Dispose()
{ {
TimelineGroupViewModel.Dispose(); LayerPropertyGroup.VisibilityChanged += LayerPropertyGroupOnVisibilityChanged;
LayerPropertyGroup.VisibilityChanged -= LayerPropertyGroupOnVisibilityChanged;
foreach (PropertyChangedBase child in Children) PopulateChildren();
{
if (child is IDisposable disposableChild) base.OnInitialActivate();
disposableChild.Dispose();
}
} }
#endregion protected override void OnClose()
{
LayerPropertyGroup.VisibilityChanged -= LayerPropertyGroupOnVisibilityChanged;
base.OnClose();
}
public void UpdateOrder(int order) public void UpdateOrder(int order)
{ {
LayerPropertyGroup.LayerEffect.Order = order; if (LayerPropertyGroup.LayerEffect != null)
LayerPropertyGroup.LayerEffect.Order = order;
NotifyOfPropertyChange(nameof(IsExpanded)); NotifyOfPropertyChange(nameof(IsExpanded));
} }
@ -79,7 +91,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
if (expandedOnly && !IsExpanded) if (expandedOnly && !IsExpanded)
return result; return result;
foreach (PropertyChangedBase child in Children) foreach (Screen child in Items)
{ {
if (child is LayerPropertyViewModel layerPropertyViewModel) if (child is LayerPropertyViewModel layerPropertyViewModel)
result.AddRange(layerPropertyViewModel.TimelinePropertyViewModel.GetAllKeyframeViewModels()); result.AddRange(layerPropertyViewModel.TimelinePropertyViewModel.GetAllKeyframeViewModels());
@ -98,11 +110,11 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
/// <param name="end">The position at which to start removing keyframes, if null this will end at the last keyframe</param> /// <param name="end">The position at which to start removing keyframes, if null this will end at the last keyframe</param>
public void WipeKeyframes(TimeSpan? start, TimeSpan? end) public void WipeKeyframes(TimeSpan? start, TimeSpan? end)
{ {
foreach (PropertyChangedBase child in Children) foreach (Screen item in Items)
{ {
if (child is LayerPropertyViewModel layerPropertyViewModel) if (item is LayerPropertyViewModel layerPropertyViewModel)
layerPropertyViewModel.TimelinePropertyViewModel.WipeKeyframes(start, end); layerPropertyViewModel.TimelinePropertyViewModel.WipeKeyframes(start, end);
else if (child is LayerPropertyGroupViewModel layerPropertyGroupViewModel) else if (item is LayerPropertyGroupViewModel layerPropertyGroupViewModel)
layerPropertyGroupViewModel.WipeKeyframes(start, end); layerPropertyGroupViewModel.WipeKeyframes(start, end);
} }
@ -118,11 +130,11 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
/// <param name="amount">The amount to shift the keyframes for</param> /// <param name="amount">The amount to shift the keyframes for</param>
public void ShiftKeyframes(TimeSpan? start, TimeSpan? end, TimeSpan amount) public void ShiftKeyframes(TimeSpan? start, TimeSpan? end, TimeSpan amount)
{ {
foreach (PropertyChangedBase child in Children) foreach (Screen item in Items)
{ {
if (child is LayerPropertyViewModel layerPropertyViewModel) if (item is LayerPropertyViewModel layerPropertyViewModel)
layerPropertyViewModel.TimelinePropertyViewModel.ShiftKeyframes(start, end, amount); layerPropertyViewModel.TimelinePropertyViewModel.ShiftKeyframes(start, end, amount);
else if (child is LayerPropertyGroupViewModel layerPropertyGroupViewModel) else if (item is LayerPropertyGroupViewModel layerPropertyGroupViewModel)
layerPropertyGroupViewModel.ShiftKeyframes(start, end, amount); layerPropertyGroupViewModel.ShiftKeyframes(start, end, amount);
} }
@ -147,16 +159,13 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
// Create VMs for properties on the group // Create VMs for properties on the group
if (propertyAttribute != null && value is ILayerProperty layerProperty) if (propertyAttribute != null && value is ILayerProperty layerProperty)
{ {
LayerPropertyViewModel layerPropertyViewModel = _layerPropertyVmFactory.LayerPropertyViewModel(layerProperty); // Ensure a supported input VM was found, otherwise don't add it
// After creation ensure a supported input VM was found, if not, discard the VM if (_profileEditorService.CanCreatePropertyInputViewModel(layerProperty))
if (!layerPropertyViewModel.TreePropertyViewModel.HasPropertyInputViewModel) Items.Add(_layerPropertyVmFactory.LayerPropertyViewModel(layerProperty));
layerPropertyViewModel.Dispose();
else
Children.Add(layerPropertyViewModel);
} }
// Create VMs for child groups on this group, resulting in a nested structure // Create VMs for child groups on this group, resulting in a nested structure
else if (groupAttribute != null && value is LayerPropertyGroup layerPropertyGroup) else if (groupAttribute != null && value is LayerPropertyGroup layerPropertyGroup)
Children.Add(_layerPropertyVmFactory.LayerPropertyGroupViewModel(layerPropertyGroup)); Items.Add(_layerPropertyVmFactory.LayerPropertyGroupViewModel(layerPropertyGroup));
} }
} }
} }

View File

@ -1,5 +1,4 @@
using System; 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.Timeline;
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree; using Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree;
@ -7,23 +6,38 @@ using Stylet;
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
{ {
public sealed class LayerPropertyViewModel : PropertyChangedBase, IDisposable public sealed class LayerPropertyViewModel : Screen
{ {
private bool _isVisible;
private bool _isHighlighted;
private bool _isExpanded; private bool _isExpanded;
private bool _isHighlighted;
private bool _isVisible;
private ITimelinePropertyViewModel _timelinePropertyViewModel;
private ITreePropertyViewModel _treePropertyViewModel;
public LayerPropertyViewModel(ILayerProperty layerProperty, IPropertyVmFactory propertyVmFactory) public LayerPropertyViewModel(ILayerProperty layerProperty, IPropertyVmFactory propertyVmFactory)
{ {
LayerProperty = layerProperty; LayerProperty = layerProperty;
TreePropertyViewModel = propertyVmFactory.TreePropertyViewModel(layerProperty, this); TreePropertyViewModel = propertyVmFactory.TreePropertyViewModel(LayerProperty, this);
TimelinePropertyViewModel = propertyVmFactory.TimelinePropertyViewModel(layerProperty, this); TreePropertyViewModel.ConductWith(this);
TimelinePropertyViewModel = propertyVmFactory.TimelinePropertyViewModel(LayerProperty, this);
TimelinePropertyViewModel.ConductWith(this);
} }
public ILayerProperty LayerProperty { get; } public ILayerProperty LayerProperty { get; }
public ITreePropertyViewModel TreePropertyViewModel { get; }
public ITimelinePropertyViewModel TimelinePropertyViewModel { get; } public ITreePropertyViewModel TreePropertyViewModel
{
get => _treePropertyViewModel;
set => SetAndNotify(ref _treePropertyViewModel, value);
}
public ITimelinePropertyViewModel TimelinePropertyViewModel
{
get => _timelinePropertyViewModel;
set => SetAndNotify(ref _timelinePropertyViewModel, value);
}
public bool IsVisible public bool IsVisible
{ {
@ -42,11 +56,5 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
get => _isExpanded; get => _isExpanded;
set => SetAndNotify(ref _isExpanded, value); set => SetAndNotify(ref _isExpanded, value);
} }
public void Dispose()
{
TreePropertyViewModel?.Dispose();
TimelinePropertyViewModel?.Dispose();
}
} }
} }

View File

@ -48,7 +48,7 @@
<Rectangle Grid.Row="1" HorizontalAlignment="Stretch" Fill="{DynamicResource MaterialDesignDivider}" Height="1" /> <Rectangle Grid.Row="1" HorizontalAlignment="Stretch" Fill="{DynamicResource MaterialDesignDivider}" Height="1" />
<ItemsControl Grid.Row="2" <ItemsControl Grid.Row="2"
ItemsSource="{Binding LayerPropertyGroupViewModel.Children}" ItemsSource="{Binding LayerPropertyGroupViewModel.Items}"
Visibility="{Binding LayerPropertyGroupViewModel.IsExpanded, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" Visibility="{Binding LayerPropertyGroupViewModel.IsExpanded, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch"> HorizontalContentAlignment="Stretch">

View File

@ -7,7 +7,7 @@ using Stylet;
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
{ {
public sealed class TimelineGroupViewModel : PropertyChangedBase, IDisposable public sealed class TimelineGroupViewModel : Screen
{ {
private readonly IProfileEditorService _profileEditorService; private readonly IProfileEditorService _profileEditorService;
@ -19,13 +19,9 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
LayerPropertyGroup = LayerPropertyGroupViewModel.LayerPropertyGroup; LayerPropertyGroup = LayerPropertyGroupViewModel.LayerPropertyGroup;
KeyframePositions = new BindableCollection<double>(); KeyframePositions = new BindableCollection<double>();
_profileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged; UpdateKeyframePositions();
LayerPropertyGroupViewModel.PropertyChanged += LayerPropertyGroupViewModelOnPropertyChanged;
UpdateKeyframePositions();
} }
public LayerPropertyGroupViewModel LayerPropertyGroupViewModel { get; } public LayerPropertyGroupViewModel LayerPropertyGroupViewModel { get; }
public LayerPropertyGroup LayerPropertyGroup { get; } public LayerPropertyGroup LayerPropertyGroup { get; }
@ -39,16 +35,26 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
.Select(p => p.Position.TotalSeconds * _profileEditorService.PixelsPerSecond)); .Select(p => p.Position.TotalSeconds * _profileEditorService.PixelsPerSecond));
} }
#region IDisposable #region Overrides of Screen
public void Dispose() /// <inheritdoc />
protected override void OnInitialActivate()
{
_profileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
LayerPropertyGroupViewModel.PropertyChanged += LayerPropertyGroupViewModelOnPropertyChanged;
base.OnInitialActivate();
}
/// <inheritdoc />
protected override void OnClose()
{ {
_profileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged; _profileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
LayerPropertyGroupViewModel.PropertyChanged -= LayerPropertyGroupViewModelOnPropertyChanged; LayerPropertyGroupViewModel.PropertyChanged -= LayerPropertyGroupViewModelOnPropertyChanged;
base.OnClose();
} }
#endregion #endregion
#region Event handlers #region Event handlers
private void LayerPropertyGroupViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e) private void LayerPropertyGroupViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e)

View File

@ -20,12 +20,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
_profileEditorService = profileEditorService; _profileEditorService = profileEditorService;
LayerPropertyKeyframe = layerPropertyKeyframe; LayerPropertyKeyframe = layerPropertyKeyframe;
EasingViewModels = new BindableCollection<TimelineEasingViewModel>(); EasingViewModels = new BindableCollection<TimelineEasingViewModel>();
_profileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
LayerPropertyKeyframe.PropertyChanged += LayerPropertyKeyframeOnPropertyChanged;
} }
public LayerPropertyKeyframe<T> LayerPropertyKeyframe { get; } public LayerPropertyKeyframe<T> LayerPropertyKeyframe { get; }
public BindableCollection<TimelineEasingViewModel> EasingViewModels { get; } public BindableCollection<TimelineEasingViewModel> EasingViewModels { get; }
@ -50,15 +46,29 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
public TimeSpan Position => LayerPropertyKeyframe.Position; public TimeSpan Position => LayerPropertyKeyframe.Position;
public ILayerPropertyKeyframe Keyframe => LayerPropertyKeyframe; public ILayerPropertyKeyframe Keyframe => LayerPropertyKeyframe;
public void Dispose() #region Overrides of Screen
protected override void OnInitialActivate()
{
_profileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
LayerPropertyKeyframe.PropertyChanged += LayerPropertyKeyframeOnPropertyChanged;
base.OnInitialActivate();
}
protected override void OnClose()
{ {
_profileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged; _profileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
LayerPropertyKeyframe.PropertyChanged -= LayerPropertyKeyframeOnPropertyChanged; LayerPropertyKeyframe.PropertyChanged -= LayerPropertyKeyframeOnPropertyChanged;
foreach (TimelineEasingViewModel timelineEasingViewModel in EasingViewModels) foreach (TimelineEasingViewModel timelineEasingViewModel in EasingViewModels)
timelineEasingViewModel.EasingModeSelected -= TimelineEasingViewModelOnEasingModeSelected; timelineEasingViewModel.EasingModeSelected -= TimelineEasingViewModelOnEasingModeSelected;
base.OnClose();
} }
#endregion
public void Update() public void Update()
{ {
X = _profileEditorService.PixelsPerSecond * LayerPropertyKeyframe.Position.TotalSeconds; X = _profileEditorService.PixelsPerSecond * LayerPropertyKeyframe.Position.TotalSeconds;
@ -159,7 +169,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
#endregion #endregion
#region Context menu actions #region Context menu actions
public void Delete(bool save = true) public void Delete(bool save = true)
{ {
LayerPropertyKeyframe.LayerProperty.RemoveKeyframe(LayerPropertyKeyframe); LayerPropertyKeyframe.LayerProperty.RemoveKeyframe(LayerPropertyKeyframe);
@ -170,7 +180,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
#endregion #endregion
} }
public interface ITimelineKeyframeViewModel : IScreen, IDisposable public interface ITimelineKeyframeViewModel : IScreen
{ {
bool IsSelected { get; set; } bool IsSelected { get; set; }
TimeSpan Position { get; } TimeSpan Position { get; }

View File

@ -10,9 +10,7 @@
d:DesignHeight="450" d:DesignWidth="800" d:DesignHeight="450" d:DesignWidth="800"
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 Items}" <ItemsControl ItemsSource="{Binding Items}" Background="{DynamicResource MaterialDesignToolBarBackground}" HorizontalAlignment="Left">
Background="{DynamicResource MaterialDesignToolBarBackground}"
HorizontalAlignment="Left">
<ItemsControl.ItemsPanel> <ItemsControl.ItemsPanel>
<ItemsPanelTemplate> <ItemsPanelTemplate>
<Canvas /> <Canvas />

View File

@ -18,11 +18,6 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
LayerProperty = layerProperty; LayerProperty = layerProperty;
LayerPropertyViewModel = layerPropertyViewModel; LayerPropertyViewModel = layerPropertyViewModel;
LayerProperty.KeyframesToggled += LayerPropertyOnKeyframesToggled;
LayerProperty.KeyframeAdded += LayerPropertyOnKeyframeAdded;
LayerProperty.KeyframeRemoved += LayerPropertyOnKeyframeRemoved;
UpdateKeyframes();
} }
public LayerProperty<T> LayerProperty { get; } public LayerProperty<T> LayerProperty { get; }
@ -59,15 +54,27 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
List<LayerPropertyKeyframe<T>> toShift = LayerProperty.Keyframes.Where(k => k.Position > start && k.Position < end).ToList(); List<LayerPropertyKeyframe<T>> toShift = LayerProperty.Keyframes.Where(k => k.Position > start && k.Position < end).ToList();
foreach (LayerPropertyKeyframe<T> keyframe in toShift) foreach (LayerPropertyKeyframe<T> keyframe in toShift)
keyframe.Position += amount; keyframe.Position += amount;
UpdateKeyframes(); UpdateKeyframes();
} }
public void Dispose() protected override void OnClose()
{ {
LayerProperty.KeyframesToggled -= LayerPropertyOnKeyframesToggled; LayerProperty.KeyframesToggled -= LayerPropertyOnKeyframesToggled;
LayerProperty.KeyframeAdded -= LayerPropertyOnKeyframeAdded; LayerProperty.KeyframeAdded -= LayerPropertyOnKeyframeAdded;
LayerProperty.KeyframeRemoved -= LayerPropertyOnKeyframeRemoved; LayerProperty.KeyframeRemoved -= LayerPropertyOnKeyframeRemoved;
base.OnClose();
}
protected override void OnInitialActivate()
{
LayerProperty.KeyframesToggled += LayerPropertyOnKeyframesToggled;
LayerProperty.KeyframeAdded += LayerPropertyOnKeyframeAdded;
LayerProperty.KeyframeRemoved += LayerPropertyOnKeyframeRemoved;
UpdateKeyframes();
base.OnInitialActivate();
} }
private void LayerPropertyOnKeyframesToggled(object sender, LayerPropertyEventArgs<T> e) private void LayerPropertyOnKeyframesToggled(object sender, LayerPropertyEventArgs<T> e)
@ -92,14 +99,10 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
if (LayerProperty.KeyframesEnabled) if (LayerProperty.KeyframesEnabled)
{ {
List<LayerPropertyKeyframe<T>> keyframes = LayerProperty.Keyframes.ToList(); List<LayerPropertyKeyframe<T>> keyframes = LayerProperty.Keyframes.ToList();
List<TimelineKeyframeViewModel<T>> toRemove = Items.Where(t => !keyframes.Contains(t.LayerPropertyKeyframe)).ToList();
foreach (TimelineKeyframeViewModel<T> timelineKeyframeViewModel in toRemove)
timelineKeyframeViewModel.Dispose();
Items.RemoveRange(toRemove); Items.RemoveRange(Items.Where(t => !keyframes.Contains(t.LayerPropertyKeyframe)).ToList());
Items.AddRange(keyframes Items.AddRange(
.Where(k => Items.All(t => t.LayerPropertyKeyframe != k)) keyframes.Where(k => Items.All(t => t.LayerPropertyKeyframe != k)).Select(k => new TimelineKeyframeViewModel<T>(k, _profileEditorService))
.Select(k => new TimelineKeyframeViewModel<T>(k, _profileEditorService))
); );
} }
else else
@ -110,7 +113,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
} }
} }
public interface ITimelinePropertyViewModel : IScreen, IDisposable public interface ITimelinePropertyViewModel : IScreen
{ {
List<ITimelineKeyframeViewModel> GetAllKeyframeViewModels(); List<ITimelineKeyframeViewModel> GetAllKeyframeViewModels();
void WipeKeyframes(TimeSpan? start, TimeSpan? end); void WipeKeyframes(TimeSpan? start, TimeSpan? end);

View File

@ -14,7 +14,7 @@ using Stylet;
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
{ {
public sealed class TimelineSegmentViewModel : Screen, IDisposable public sealed class TimelineSegmentViewModel : Screen
{ {
private readonly IDialogService _dialogService; private readonly IDialogService _dialogService;
private bool _draggingSegment; private bool _draggingSegment;
@ -28,7 +28,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
private bool _showRepeatButton; private bool _showRepeatButton;
private bool _showSegmentName; private bool _showSegmentName;
public TimelineSegmentViewModel(SegmentViewModelType segment, BindableCollection<LayerPropertyGroupViewModel> layerPropertyGroups, public TimelineSegmentViewModel(SegmentViewModelType segment, IObservableCollection<LayerPropertyGroupViewModel> layerPropertyGroups,
IProfileEditorService profileEditorService, IDialogService dialogService) IProfileEditorService profileEditorService, IDialogService dialogService)
{ {
_dialogService = dialogService; _dialogService = dialogService;
@ -43,18 +43,11 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
else if (Segment == SegmentViewModelType.End) else if (Segment == SegmentViewModelType.End)
ToolTip = "This segment is played once a condition is no longer met"; ToolTip = "This segment is played once a condition is no longer met";
IsMainSegment = Segment == SegmentViewModelType.Main; IsMainSegment = Segment == SegmentViewModelType.Main;
ProfileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
ProfileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected;
if (ProfileEditorService.SelectedProfileElement != null)
ProfileEditorService.SelectedProfileElement.Timeline.PropertyChanged += TimelineOnPropertyChanged;
Update();
} }
public RenderProfileElement SelectedProfileElement => ProfileEditorService.SelectedProfileElement; public RenderProfileElement SelectedProfileElement => ProfileEditorService.SelectedProfileElement;
public SegmentViewModelType Segment { get; } public SegmentViewModelType Segment { get; }
public BindableCollection<LayerPropertyGroupViewModel> LayerPropertyGroups { get; } public IObservableCollection<LayerPropertyGroupViewModel> LayerPropertyGroups { get; }
public IProfileEditorService ProfileEditorService { get; } public IProfileEditorService ProfileEditorService { get; }
public string ToolTip { get; } public string ToolTip { get; }
@ -160,14 +153,28 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
layerPropertyGroupViewModel.ShiftKeyframes(start, end, amount); layerPropertyGroupViewModel.ShiftKeyframes(start, end, amount);
} }
#region IDIsposable #region Overrides of Screen
public void Dispose() /// <inheritdoc />
protected override void OnInitialActivate()
{
ProfileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
ProfileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected;
if (ProfileEditorService.SelectedProfileElement != null)
ProfileEditorService.SelectedProfileElement.Timeline.PropertyChanged += TimelineOnPropertyChanged;
Update();
base.OnInitialActivate();
}
/// <inheritdoc />
protected override void OnClose()
{ {
ProfileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged; ProfileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
ProfileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected; ProfileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected;
if (SelectedProfileElement != null) if (SelectedProfileElement != null)
SelectedProfileElement.Timeline.PropertyChanged -= TimelineOnPropertyChanged; SelectedProfileElement.Timeline.PropertyChanged -= TimelineOnPropertyChanged;
base.OnClose();
} }
#endregion #endregion

View File

@ -11,33 +11,26 @@ using Artemis.Core;
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline.Models; using Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline.Models;
using Artemis.UI.Shared; using Artemis.UI.Shared;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.Models;
using Stylet; using Stylet;
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
{ {
public sealed class TimelineViewModel : Screen, IDisposable public sealed class TimelineViewModel : Screen
{ {
private readonly IProfileEditorService _profileEditorService; private readonly IProfileEditorService _profileEditorService;
private RectangleGeometry _selectionRectangle; private RectangleGeometry _selectionRectangle;
public TimelineViewModel(LayerPropertiesViewModel layerPropertiesViewModel, BindableCollection<LayerPropertyGroupViewModel> layerPropertyGroups, IProfileEditorService profileEditorService) public TimelineViewModel(LayerPropertiesViewModel layerPropertiesViewModel, IObservableCollection<LayerPropertyGroupViewModel> layerPropertyGroups, IProfileEditorService profileEditorService)
{ {
_profileEditorService = profileEditorService; _profileEditorService = profileEditorService;
LayerPropertiesViewModel = layerPropertiesViewModel; LayerPropertiesViewModel = layerPropertiesViewModel;
LayerPropertyGroups = layerPropertyGroups; LayerPropertyGroups = layerPropertyGroups;
SelectionRectangle = new RectangleGeometry(); SelectionRectangle = new RectangleGeometry();
_profileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
_profileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected;
if (_profileEditorService.SelectedProfileElement != null)
_profileEditorService.SelectedProfileElement.Timeline.PropertyChanged += TimelineOnPropertyChanged;
Update();
} }
public LayerPropertiesViewModel LayerPropertiesViewModel { get; } public LayerPropertiesViewModel LayerPropertiesViewModel { get; }
public BindableCollection<LayerPropertyGroupViewModel> LayerPropertyGroups { get; } public IObservableCollection<LayerPropertyGroupViewModel> LayerPropertyGroups { get; }
public RectangleGeometry SelectionRectangle public RectangleGeometry SelectionRectangle
{ {
@ -101,14 +94,27 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline
Update(); Update();
} }
#region IDisposable #region Overrides of Screen
public void Dispose() /// <inheritdoc />
protected override void OnInitialActivate()
{
_profileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
_profileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected;
if (_profileEditorService.SelectedProfileElement != null)
_profileEditorService.SelectedProfileElement.Timeline.PropertyChanged += TimelineOnPropertyChanged;
Update();
base.OnInitialActivate();
}
/// <inheritdoc />
protected override void OnClose()
{ {
_profileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged; _profileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
_profileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected; _profileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected;
if (_profileEditorService.SelectedProfileElement != null) if (_profileEditorService.SelectedProfileElement != null)
_profileEditorService.SelectedProfileElement.Timeline.PropertyChanged -= TimelineOnPropertyChanged; _profileEditorService.SelectedProfileElement.Timeline.PropertyChanged -= TimelineOnPropertyChanged;
base.OnClose();
} }
#endregion #endregion

View File

@ -224,7 +224,7 @@
Do not bind directly to the LayerPropertyGroupViewModel.Children collection Do not bind directly to the LayerPropertyGroupViewModel.Children collection
Instead use a reference provided by the VM that is null when collapsed, virtualization for noobs Instead use a reference provided by the VM that is null when collapsed, virtualization for noobs
--> -->
<ItemsControl ItemsSource="{Binding Children}" <ItemsControl ItemsSource="{Binding Items}"
Visibility="{Binding LayerPropertyGroupViewModel.IsExpanded, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" Visibility="{Binding LayerPropertyGroupViewModel.IsExpanded, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
HorizontalContentAlignment="Stretch" HorizontalContentAlignment="Stretch"

View File

@ -18,7 +18,7 @@ using Stylet;
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
{ {
public class TreeGroupViewModel : PropertyChangedBase public class TreeGroupViewModel : Screen
{ {
public enum LayerPropertyGroupType public enum LayerPropertyGroupType
{ {
@ -30,27 +30,18 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
} }
private readonly IDialogService _dialogService; private readonly IDialogService _dialogService;
private readonly IKernel _kernel;
private readonly IProfileEditorService _profileEditorService; private readonly IProfileEditorService _profileEditorService;
private readonly IWindowManager _windowManager; private readonly IWindowManager _windowManager;
public TreeGroupViewModel( public TreeGroupViewModel(LayerPropertyGroupViewModel layerPropertyGroupViewModel, IProfileEditorService profileEditorService, IDialogService dialogService, IWindowManager windowManager)
LayerPropertyGroupViewModel layerPropertyGroupViewModel,
IProfileEditorService profileEditorService,
IDialogService dialogService,
IWindowManager windowManager,
IKernel kernel)
{ {
_profileEditorService = profileEditorService; _profileEditorService = profileEditorService;
_dialogService = dialogService; _dialogService = dialogService;
_windowManager = windowManager; _windowManager = windowManager;
_kernel = kernel;
LayerPropertyGroupViewModel = layerPropertyGroupViewModel; LayerPropertyGroupViewModel = layerPropertyGroupViewModel;
LayerPropertyGroup = LayerPropertyGroupViewModel.LayerPropertyGroup; LayerPropertyGroup = LayerPropertyGroupViewModel.LayerPropertyGroup;
LayerPropertyGroupViewModel.PropertyChanged += LayerPropertyGroupViewModelOnPropertyChanged;
DetermineGroupType(); DetermineGroupType();
} }
@ -58,10 +49,10 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
public LayerPropertyGroup LayerPropertyGroup { get; } public LayerPropertyGroup LayerPropertyGroup { get; }
public LayerPropertyGroupType GroupType { get; set; } public LayerPropertyGroupType GroupType { get; set; }
public BindableCollection<PropertyChangedBase> Children => public IObservableCollection<Screen> Items => LayerPropertyGroupViewModel.IsExpanded &&
LayerPropertyGroupViewModel.IsExpanded && LayerPropertyGroupViewModel.IsVisible LayerPropertyGroupViewModel.IsVisible
? LayerPropertyGroupViewModel.Children ? LayerPropertyGroupViewModel.Items
: null; : null;
public void OpenBrushSettings() public void OpenBrushSettings()
{ {
@ -164,7 +155,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
private void LayerPropertyGroupViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e) private void LayerPropertyGroupViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e)
{ {
if (e.PropertyName == nameof(LayerPropertyGroupViewModel.IsExpanded) || e.PropertyName == nameof(LayerPropertyGroupViewModel.IsVisible)) if (e.PropertyName == nameof(LayerPropertyGroupViewModel.IsExpanded) || e.PropertyName == nameof(LayerPropertyGroupViewModel.IsVisible))
NotifyOfPropertyChange(nameof(Children)); NotifyOfPropertyChange(nameof(Items));
} }
private void DetermineGroupType() private void DetermineGroupType()
@ -180,5 +171,23 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
else else
GroupType = LayerPropertyGroupType.None; GroupType = LayerPropertyGroupType.None;
} }
#region Overrides of Screen
/// <inheritdoc />
protected override void OnInitialActivate()
{
LayerPropertyGroupViewModel.PropertyChanged += LayerPropertyGroupViewModelOnPropertyChanged;
base.OnInitialActivate();
}
/// <inheritdoc />
protected override void OnClose()
{
LayerPropertyGroupViewModel.PropertyChanged -= LayerPropertyGroupViewModelOnPropertyChanged;
base.OnClose();
}
#endregion
} }
} }

View File

@ -19,12 +19,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
LayerPropertyViewModel = layerPropertyViewModel; LayerPropertyViewModel = layerPropertyViewModel;
PropertyInputViewModel = _profileEditorService.CreatePropertyInputViewModel(LayerProperty); PropertyInputViewModel = _profileEditorService.CreatePropertyInputViewModel(LayerProperty);
_profileEditorService.SelectedDataBindingChanged += ProfileEditorServiceOnSelectedDataBindingChanged; PropertyInputViewModel.ConductWith(this);
LayerProperty.VisibilityChanged += LayerPropertyOnVisibilityChanged;
LayerProperty.DataBindingEnabled += LayerPropertyOnDataBindingChange;
LayerProperty.DataBindingDisabled += LayerPropertyOnDataBindingChange;
LayerProperty.KeyframesToggled += LayerPropertyOnKeyframesToggled;
LayerPropertyViewModel.IsVisible = !LayerProperty.IsHidden;
} }
public LayerProperty<T> LayerProperty { get; } public LayerProperty<T> LayerProperty { get; }
@ -89,19 +84,30 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
return depth; return depth;
} }
#region Overrides of Screen
public bool HasPropertyInputViewModel => PropertyInputViewModel != null; /// <inheritdoc />
protected override void OnInitialActivate()
#region IDisposable {
_profileEditorService.SelectedDataBindingChanged += ProfileEditorServiceOnSelectedDataBindingChanged;
public void Dispose() LayerProperty.VisibilityChanged += LayerPropertyOnVisibilityChanged;
LayerProperty.DataBindingEnabled += LayerPropertyOnDataBindingChange;
LayerProperty.DataBindingDisabled += LayerPropertyOnDataBindingChange;
LayerProperty.KeyframesToggled += LayerPropertyOnKeyframesToggled;
LayerPropertyViewModel.IsVisible = !LayerProperty.IsHidden;
base.OnInitialActivate();
}
/// <inheritdoc />
protected override void OnClose()
{ {
_propertyInputViewModel?.Dispose();
_profileEditorService.SelectedDataBindingChanged -= ProfileEditorServiceOnSelectedDataBindingChanged; _profileEditorService.SelectedDataBindingChanged -= ProfileEditorServiceOnSelectedDataBindingChanged;
LayerProperty.VisibilityChanged -= LayerPropertyOnVisibilityChanged; LayerProperty.VisibilityChanged -= LayerPropertyOnVisibilityChanged;
LayerProperty.DataBindingEnabled -= LayerPropertyOnDataBindingChange; LayerProperty.DataBindingEnabled -= LayerPropertyOnDataBindingChange;
LayerProperty.DataBindingDisabled -= LayerPropertyOnDataBindingChange; LayerProperty.DataBindingDisabled -= LayerPropertyOnDataBindingChange;
LayerProperty.KeyframesToggled -= LayerPropertyOnKeyframesToggled; LayerProperty.KeyframesToggled -= LayerPropertyOnKeyframesToggled;
base.OnClose();
} }
#endregion #endregion
@ -131,9 +137,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
#endregion #endregion
} }
public interface ITreePropertyViewModel : IScreen, IDisposable public interface ITreePropertyViewModel : IScreen
{ {
bool HasPropertyInputViewModel { get; }
bool HasDataBinding { get; } bool HasDataBinding { get; }
double GetDepth(); double GetDepth();
} }

View File

@ -7,7 +7,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
{ {
public class TreeViewModel : Screen public class TreeViewModel : Screen
{ {
public TreeViewModel(LayerPropertiesViewModel layerPropertiesViewModel, BindableCollection<LayerPropertyGroupViewModel> layerPropertyGroups) public TreeViewModel(LayerPropertiesViewModel layerPropertiesViewModel, IObservableCollection<LayerPropertyGroupViewModel> layerPropertyGroups)
{ {
LayerPropertiesViewModel = layerPropertiesViewModel; LayerPropertiesViewModel = layerPropertiesViewModel;
@ -16,7 +16,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
} }
public LayerPropertiesViewModel LayerPropertiesViewModel { get; } public LayerPropertiesViewModel LayerPropertiesViewModel { get; }
public BindableCollection<LayerPropertyGroupViewModel> LayerPropertyGroups { get; } public IObservableCollection<LayerPropertyGroupViewModel> LayerPropertyGroups { get; }
public void PropertyTreePreviewMouseWheel(object sender, MouseWheelEventArgs e) public void PropertyTreePreviewMouseWheel(object sender, MouseWheelEventArgs e)
{ {

View File

@ -15,12 +15,11 @@ using Artemis.UI.Screens.ProfileEditor.ProfileTree;
using Artemis.UI.Screens.ProfileEditor.Visualization; using Artemis.UI.Screens.ProfileEditor.Visualization;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
using MaterialDesignThemes.Wpf; using MaterialDesignThemes.Wpf;
using Newtonsoft.Json;
using Stylet; using Stylet;
namespace Artemis.UI.Screens.ProfileEditor namespace Artemis.UI.Screens.ProfileEditor
{ {
public class ProfileEditorViewModel : Conductor<IProfileEditorPanelViewModel>.Collection.AllActive public class ProfileEditorViewModel : Screen
{ {
private readonly IModuleService _moduleService; private readonly IModuleService _moduleService;
private readonly IProfileEditorService _profileEditorService; private readonly IProfileEditorService _profileEditorService;
@ -64,14 +63,13 @@ namespace Artemis.UI.Screens.ProfileEditor
// Populate the panels // Populate the panels
ProfileViewModel = profileViewModel; ProfileViewModel = profileViewModel;
ProfileViewModel.ConductWith(this);
ProfileTreeViewModel = profileTreeViewModel; ProfileTreeViewModel = profileTreeViewModel;
ProfileTreeViewModel.ConductWith(this);
DisplayConditionsViewModel = dataModelConditionsViewModel; DisplayConditionsViewModel = dataModelConditionsViewModel;
DisplayConditionsViewModel.ConductWith(this);
LayerPropertiesViewModel = layerPropertiesViewModel; LayerPropertiesViewModel = layerPropertiesViewModel;
LayerPropertiesViewModel.ConductWith(this);
Items.Add(ProfileViewModel);
Items.Add(ProfileTreeViewModel);
Items.Add(dataModelConditionsViewModel);
Items.Add(LayerPropertiesViewModel);
} }
public ProfileModule Module { get; } public ProfileModule Module { get; }

View File

@ -1,9 +1,8 @@
using System; using Stylet;
using Stylet;
namespace Artemis.UI.Screens.ProfileEditor.Visualization namespace Artemis.UI.Screens.ProfileEditor.Visualization
{ {
public abstract class CanvasViewModel : PropertyChangedBase, IDisposable public abstract class CanvasViewModel : Screen
{ {
private double _x; private double _x;
private double _y; private double _y;
@ -19,18 +18,5 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
get => _y; get => _y;
set => SetAndNotify(ref _y, value); set => SetAndNotify(ref _y, value);
} }
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (disposing)
{
}
}
} }
} }

View File

@ -5,9 +5,9 @@ using System.Windows;
using System.Windows.Media; using System.Windows.Media;
using Artemis.Core; using Artemis.Core;
using Artemis.UI.Extensions; using Artemis.UI.Extensions;
using Artemis.UI.Screens.Shared;
using Artemis.UI.Services.Interfaces; using Artemis.UI.Services.Interfaces;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
using Stylet;
namespace Artemis.UI.Screens.ProfileEditor.Visualization namespace Artemis.UI.Screens.ProfileEditor.Visualization
{ {
@ -15,25 +15,17 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
{ {
private readonly ILayerEditorService _layerEditorService; private readonly ILayerEditorService _layerEditorService;
private readonly IProfileEditorService _profileEditorService; private readonly IProfileEditorService _profileEditorService;
private readonly ProfileViewModel _profileViewModel; private readonly PanZoomViewModel _panZoomViewModel;
private bool _isSelected; private bool _isSelected;
private Geometry _shapeGeometry; private Geometry _shapeGeometry;
private Rect _viewportRectangle; private Rect _viewportRectangle;
public ProfileLayerViewModel(Layer layer, ProfileViewModel profileViewModel, IProfileEditorService profileEditorService, ILayerEditorService layerEditorService) public ProfileLayerViewModel(Layer layer, PanZoomViewModel panZoomViewModel, IProfileEditorService profileEditorService, ILayerEditorService layerEditorService)
{ {
_profileViewModel = profileViewModel; _panZoomViewModel = panZoomViewModel;
_profileEditorService = profileEditorService; _profileEditorService = profileEditorService;
_layerEditorService = layerEditorService; _layerEditorService = layerEditorService;
Layer = layer; Layer = layer;
Update();
Layer.RenderPropertiesUpdated += LayerOnRenderPropertiesUpdated;
_profileEditorService.ProfileElementSelected += OnProfileElementSelected;
_profileEditorService.SelectedProfileElementUpdated += OnSelectedProfileElementUpdated;
_profileEditorService.ProfilePreviewUpdated += ProfileEditorServiceOnProfilePreviewUpdated;
_profileViewModel.PanZoomViewModel.PropertyChanged += PanZoomViewModelOnPropertyChanged;
} }
public Layer Layer { get; } public Layer Layer { get; }
@ -59,8 +51,8 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
get get
{ {
if (IsSelected) if (IsSelected)
return Math.Max(2 / _profileViewModel.PanZoomViewModel.Zoom, 1); return Math.Max(2 / _panZoomViewModel.Zoom, 1);
return Math.Max(2 / _profileViewModel.PanZoomViewModel.Zoom, 1) / 2; return Math.Max(2 / _panZoomViewModel.Zoom, 1) / 2;
} }
} }
@ -86,23 +78,9 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
} }
} }
protected override void Dispose(bool disposing)
{
if (disposing)
{
Layer.RenderPropertiesUpdated -= LayerOnRenderPropertiesUpdated;
_profileEditorService.ProfileElementSelected -= OnProfileElementSelected;
_profileEditorService.SelectedProfileElementUpdated -= OnSelectedProfileElementUpdated;
_profileEditorService.ProfilePreviewUpdated -= ProfileEditorServiceOnProfilePreviewUpdated;
_profileViewModel.PanZoomViewModel.PropertyChanged -= PanZoomViewModelOnPropertyChanged;
}
base.Dispose(disposing);
}
private void PanZoomViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e) private void PanZoomViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e)
{ {
if (e.PropertyName == nameof(_profileViewModel.PanZoomViewModel.Zoom)) if (e.PropertyName == nameof(_panZoomViewModel.Zoom))
{ {
NotifyOfPropertyChange(nameof(StrokeThickness)); NotifyOfPropertyChange(nameof(StrokeThickness));
NotifyOfPropertyChange(nameof(LayerStrokeThickness)); NotifyOfPropertyChange(nameof(LayerStrokeThickness));
@ -193,6 +171,33 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
} }
} }
#region Overrides of Screen
/// <inheritdoc />
protected override void OnInitialActivate()
{
Update();
Layer.RenderPropertiesUpdated += LayerOnRenderPropertiesUpdated;
_profileEditorService.ProfileElementSelected += OnProfileElementSelected;
_profileEditorService.SelectedProfileElementUpdated += OnSelectedProfileElementUpdated;
_profileEditorService.ProfilePreviewUpdated += ProfileEditorServiceOnProfilePreviewUpdated;
_panZoomViewModel.PropertyChanged += PanZoomViewModelOnPropertyChanged;
base.OnInitialActivate();
}
/// <inheritdoc />
protected override void OnClose()
{
Layer.RenderPropertiesUpdated -= LayerOnRenderPropertiesUpdated;
_profileEditorService.ProfileElementSelected -= OnProfileElementSelected;
_profileEditorService.SelectedProfileElementUpdated -= OnSelectedProfileElementUpdated;
_profileEditorService.ProfilePreviewUpdated -= ProfileEditorServiceOnProfilePreviewUpdated;
_panZoomViewModel.PropertyChanged -= PanZoomViewModelOnPropertyChanged;
base.OnClose();
}
#endregion
#region Event handlers #region Event handlers
private void LayerOnRenderPropertiesUpdated(object sender, EventArgs e) private void LayerOnRenderPropertiesUpdated(object sender, EventArgs e)

View File

@ -106,7 +106,7 @@
<TranslateTransform X="{Binding PanZoomViewModel.PanX}" Y="{Binding PanZoomViewModel.PanY}" /> <TranslateTransform X="{Binding PanZoomViewModel.PanX}" Y="{Binding PanZoomViewModel.PanY}" />
</TransformGroup> </TransformGroup>
</Grid.RenderTransform> </Grid.RenderTransform>
<ItemsControl ItemsSource="{Binding CanvasViewModels}"> <ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel> <ItemsControl.ItemsPanel>
<ItemsPanelTemplate> <ItemsPanelTemplate>
<Canvas /> <Canvas />

View File

@ -15,7 +15,7 @@ using Stylet;
namespace Artemis.UI.Screens.ProfileEditor.Visualization namespace Artemis.UI.Screens.ProfileEditor.Visualization
{ {
public class ProfileViewModel : Screen, IProfileEditorPanelViewModel, IHandle<MainWindowFocusChangedEvent>, IHandle<MainWindowKeyEvent> public class ProfileViewModel : Conductor<CanvasViewModel>.Collection.AllActive, IProfileEditorPanelViewModel, IHandle<MainWindowFocusChangedEvent>, IHandle<MainWindowKeyEvent>
{ {
private readonly IProfileEditorService _profileEditorService; private readonly IProfileEditorService _profileEditorService;
private readonly ICoreService _coreService; private readonly ICoreService _coreService;
@ -28,7 +28,6 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
private VisualizationToolViewModel _activeToolViewModel; private VisualizationToolViewModel _activeToolViewModel;
private bool _canApplyToLayer; private bool _canApplyToLayer;
private bool _canSelectEditTool; private bool _canSelectEditTool;
private BindableCollection<CanvasViewModel> _canvasViewModels;
private BindableCollection<ArtemisDevice> _devices; private BindableCollection<ArtemisDevice> _devices;
private BindableCollection<ArtemisLed> _highlightedLeds; private BindableCollection<ArtemisLed> _highlightedLeds;
private PluginSetting<bool> _highlightSelectedLayer; private PluginSetting<bool> _highlightSelectedLayer;
@ -36,7 +35,6 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
private PanZoomViewModel _panZoomViewModel; private PanZoomViewModel _panZoomViewModel;
private Layer _previousSelectedLayer; private Layer _previousSelectedLayer;
private int _previousTool; private int _previousTool;
private BindableCollection<ArtemisLed> _selectedLeds;
private DateTime _lastUpdate; private DateTime _lastUpdate;
public ProfileViewModel(IProfileEditorService profileEditorService, public ProfileViewModel(IProfileEditorService profileEditorService,
@ -54,22 +52,10 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
_visualizationToolVmFactory = visualizationToolVmFactory; _visualizationToolVmFactory = visualizationToolVmFactory;
_profileLayerVmFactory = profileLayerVmFactory; _profileLayerVmFactory = profileLayerVmFactory;
Execute.OnUIThreadSync(() =>
{
PanZoomViewModel = new PanZoomViewModel {LimitToZero = false};
CanvasViewModels = new BindableCollection<CanvasViewModel>();
Devices = new BindableCollection<ArtemisDevice>();
HighlightedLeds = new BindableCollection<ArtemisLed>();
SelectedLeds = new BindableCollection<ArtemisLed>();
});
ApplySurfaceConfiguration(_surfaceService.ActiveSurface);
ActivateToolByIndex(0);
eventAggregator.Subscribe(this); eventAggregator.Subscribe(this);
} }
public bool CanSelectEditTool public bool CanSelectEditTool
{ {
get => _canSelectEditTool; get => _canSelectEditTool;
@ -82,12 +68,6 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
set => SetAndNotify(ref _panZoomViewModel, value); set => SetAndNotify(ref _panZoomViewModel, value);
} }
public BindableCollection<CanvasViewModel> CanvasViewModels
{
get => _canvasViewModels;
set => SetAndNotify(ref _canvasViewModels, value);
}
public BindableCollection<ArtemisDevice> Devices public BindableCollection<ArtemisDevice> Devices
{ {
get => _devices; get => _devices;
@ -100,12 +80,6 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
set => SetAndNotify(ref _highlightedLeds, value); set => SetAndNotify(ref _highlightedLeds, value);
} }
public BindableCollection<ArtemisLed> SelectedLeds
{
get => _selectedLeds;
set => SetAndNotify(ref _selectedLeds, value);
}
public PluginSetting<bool> AlwaysApplyDataBindings public PluginSetting<bool> AlwaysApplyDataBindings
{ {
get => _alwaysApplyDataBindings; get => _alwaysApplyDataBindings;
@ -126,10 +100,10 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
// Remove the tool from the canvas // Remove the tool from the canvas
if (_activeToolViewModel != null) if (_activeToolViewModel != null)
{ {
lock (CanvasViewModels) lock (Items)
{ {
CanvasViewModels.Remove(_activeToolViewModel); Items.Remove(_activeToolViewModel);
NotifyOfPropertyChange(() => CanvasViewModels); NotifyOfPropertyChange(() => Items);
} }
} }
@ -138,10 +112,10 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
// Add the new tool to the canvas // Add the new tool to the canvas
if (_activeToolViewModel != null) if (_activeToolViewModel != null)
{ {
lock (CanvasViewModels) lock (Items)
{ {
CanvasViewModels.Add(_activeToolViewModel); Items.Add(_activeToolViewModel);
NotifyOfPropertyChange(() => CanvasViewModels); NotifyOfPropertyChange(() => Items);
} }
} }
} }
@ -163,15 +137,16 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
set => SetAndNotify(ref _canApplyToLayer, value); set => SetAndNotify(ref _canApplyToLayer, value);
} }
public List<ArtemisLed> GetLedsInRectangle(Rect selectedRect)
{
return Devices.SelectMany(d => d.Leds)
.Where(led => led.RgbLed.AbsoluteLedRectangle.ToWindowsRect(1).IntersectsWith(selectedRect))
.ToList();
}
protected override void OnInitialActivate() protected override void OnInitialActivate()
{ {
PanZoomViewModel = new PanZoomViewModel {LimitToZero = false};
Devices = new BindableCollection<ArtemisDevice>();
HighlightedLeds = new BindableCollection<ArtemisLed>();
ApplySurfaceConfiguration(_surfaceService.ActiveSurface);
ActivateToolByIndex(0);
ApplyActiveProfile(); ApplyActiveProfile();
AlwaysApplyDataBindings = _settingsService.GetSetting("ProfileEditor.AlwaysApplyDataBindings", true); AlwaysApplyDataBindings = _settingsService.GetSetting("ProfileEditor.AlwaysApplyDataBindings", true);
@ -203,10 +178,6 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
AlwaysApplyDataBindings.Save(); AlwaysApplyDataBindings.Save();
HighlightSelectedLayer.Save(); HighlightSelectedLayer.Save();
foreach (CanvasViewModel canvasViewModel in CanvasViewModels)
canvasViewModel.Dispose();
CanvasViewModels.Clear();
base.OnClose(); base.OnClose();
} }
@ -217,23 +188,20 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
private void ApplyActiveProfile() private void ApplyActiveProfile()
{ {
List<ProfileLayerViewModel> layerViewModels = CanvasViewModels.Where(vm => vm is ProfileLayerViewModel).Cast<ProfileLayerViewModel>().ToList(); List<ProfileLayerViewModel> layerViewModels = Items.Where(vm => vm is ProfileLayerViewModel).Cast<ProfileLayerViewModel>().ToList();
List<Layer> layers = _profileEditorService.SelectedProfile?.GetAllLayers() ?? new List<Layer>(); List<Layer> layers = _profileEditorService.SelectedProfile?.GetAllLayers() ?? new List<Layer>();
// Add new layers missing a VM // Add new layers missing a VM
foreach (Layer layer in layers) foreach (Layer layer in layers)
{ {
if (layerViewModels.All(vm => vm.Layer != layer)) if (layerViewModels.All(vm => vm.Layer != layer))
CanvasViewModels.Add(_profileLayerVmFactory.Create(layer, this)); Items.Add(_profileLayerVmFactory.Create(layer, PanZoomViewModel));
} }
// Remove layers that no longer exist // Remove layers that no longer exist
IEnumerable<ProfileLayerViewModel> toRemove = layerViewModels.Where(vm => !layers.Contains(vm.Layer)); IEnumerable<ProfileLayerViewModel> toRemove = layerViewModels.Where(vm => !layers.Contains(vm.Layer));
foreach (ProfileLayerViewModel profileLayerViewModel in toRemove) foreach (ProfileLayerViewModel profileLayerViewModel in toRemove)
{ Items.Remove(profileLayerViewModel);
profileLayerViewModel.Dispose();
CanvasViewModels.Remove(profileLayerViewModel);
}
} }
private void ApplySurfaceConfiguration(ArtemisSurface surface) private void ApplySurfaceConfiguration(ArtemisSurface surface)
@ -270,20 +238,19 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
private void ActivateToolByIndex(int value) private void ActivateToolByIndex(int value)
{ {
// Consider using DI if dependencies start to add up
switch (value) switch (value)
{ {
case 0: case 0:
ActiveToolViewModel = _visualizationToolVmFactory.ViewpointMoveToolViewModel(this); ActiveToolViewModel = _visualizationToolVmFactory.ViewpointMoveToolViewModel(PanZoomViewModel);
break; break;
case 1: case 1:
ActiveToolViewModel = _visualizationToolVmFactory.EditToolViewModel(this); ActiveToolViewModel = _visualizationToolVmFactory.EditToolViewModel(PanZoomViewModel);
break; break;
case 2: case 2:
ActiveToolViewModel = _visualizationToolVmFactory.SelectionToolViewModel(this); ActiveToolViewModel = _visualizationToolVmFactory.SelectionToolViewModel(PanZoomViewModel);
break; break;
case 3: case 3:
ActiveToolViewModel = _visualizationToolVmFactory.SelectionRemoveToolViewModel(this); ActiveToolViewModel = _visualizationToolVmFactory.SelectionRemoveToolViewModel(PanZoomViewModel);
break; break;
} }
@ -324,43 +291,6 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
#endregion #endregion
#region Context menu actions
public void CreateLayer()
{
}
public void ApplyToLayer()
{
if (!(_profileEditorService.SelectedProfileElement is Layer layer))
return;
layer.ClearLeds();
layer.AddLeds(SelectedLeds);
_profileEditorService.UpdateSelectedProfileElement();
}
public void SelectAll()
{
SelectedLeds.Clear();
SelectedLeds.AddRange(Devices.SelectMany(d => d.Leds));
}
public void InverseSelection()
{
List<ArtemisLed> current = SelectedLeds.ToList();
SelectedLeds.Clear();
SelectedLeds.AddRange(Devices.SelectMany(d => d.Leds).Except(current));
}
public void ClearSelection()
{
SelectedLeds.Clear();
}
#endregion
#region Event handlers #region Event handlers
private void OnFrameRendered(object sender, FrameRenderedEventArgs e) private void OnFrameRendered(object sender, FrameRenderedEventArgs e)
@ -368,7 +298,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
TimeSpan delta = DateTime.Now - _lastUpdate; TimeSpan delta = DateTime.Now - _lastUpdate;
_lastUpdate = DateTime.Now; _lastUpdate = DateTime.Now;
if (!AlwaysApplyDataBindings.Value || _profileEditorService.SelectedProfile == null || ((ProfileEditorViewModel) Parent).LayerPropertiesViewModel.Playing) if (!AlwaysApplyDataBindings.Value || _profileEditorService.SelectedProfile == null || _profileEditorService.Playing)
return; return;
foreach (IDataBindingRegistration dataBindingRegistration in _profileEditorService.SelectedProfile.GetAllFolders() foreach (IDataBindingRegistration dataBindingRegistration in _profileEditorService.SelectedProfile.GetAllFolders()

View File

@ -11,7 +11,7 @@
d:DesignWidth="800" d:DesignWidth="800"
d:DataContext="{d:DesignInstance {x:Type tools:EditToolViewModel}}"> d:DataContext="{d:DesignInstance {x:Type tools:EditToolViewModel}}">
<Canvas UseLayoutRounding="False"> <Canvas UseLayoutRounding="False">
<userControls1:LayerShapeControl Zoom="{Binding ProfileViewModel.PanZoomViewModel.Zoom}" <userControls1:LayerShapeControl Zoom="{Binding PanZoomViewModel.Zoom}"
ShapePath="{Binding ShapePath}" ShapePath="{Binding ShapePath}"
ShapeAnchor="{Binding ShapeAnchor}" ShapeAnchor="{Binding ShapeAnchor}"
ShapeGeometry="{Binding ShapeGeometry}" ShapeGeometry="{Binding ShapeGeometry}"

View File

@ -4,6 +4,7 @@ using System.Windows.Input;
using System.Windows.Media; using System.Windows.Media;
using Artemis.Core; using Artemis.Core;
using Artemis.UI.Events; using Artemis.UI.Events;
using Artemis.UI.Screens.Shared;
using Artemis.UI.Services.Interfaces; using Artemis.UI.Services.Interfaces;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
using SkiaSharp; using SkiaSharp;
@ -22,17 +23,12 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
private SKPath _shapePath; private SKPath _shapePath;
private SKPoint _topLeft; private SKPoint _topLeft;
public EditToolViewModel(ProfileViewModel profileViewModel, IProfileEditorService profileEditorService, ILayerEditorService layerEditorService) public EditToolViewModel(PanZoomViewModel panZoomViewModel, IProfileEditorService profileEditorService, ILayerEditorService layerEditorService)
: base(profileViewModel, profileEditorService) : base(panZoomViewModel, profileEditorService)
{ {
_layerEditorService = layerEditorService; _layerEditorService = layerEditorService;
Cursor = Cursors.Arrow; Cursor = Cursors.Arrow;
Update(); Update();
profileEditorService.ProfileSelected += (sender, args) => Update();
profileEditorService.ProfileElementSelected += (sender, args) => Update();
profileEditorService.SelectedProfileElementUpdated += (sender, args) => Update();
profileEditorService.ProfilePreviewUpdated += (sender, args) => Update();
} }
public SKPath ShapePath public SKPath ShapePath
@ -60,12 +56,12 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
ShapePath = _layerEditorService.GetLayerPath(layer, true, true, true); ShapePath = _layerEditorService.GetLayerPath(layer, true, true, true);
ShapeAnchor = _layerEditorService.GetLayerAnchorPosition(layer).ToSKPoint(); ShapeAnchor = _layerEditorService.GetLayerAnchorPosition(layer).ToSKPoint();
Rect layerBounds = _layerEditorService.GetLayerBounds(layer);
TransformGroup layerTransformGroup = _layerEditorService.GetLayerTransformGroup(layer);
Execute.PostToUIThread(() => Execute.PostToUIThread(() =>
{ {
RectangleGeometry shapeGeometry = new(_layerEditorService.GetLayerBounds(layer)) RectangleGeometry shapeGeometry = new(layerBounds) {Transform = layerTransformGroup};
{
Transform = _layerEditorService.GetLayerTransformGroup(layer)
};
shapeGeometry.Freeze(); shapeGeometry.Freeze();
ShapeGeometry = shapeGeometry; ShapeGeometry = shapeGeometry;
}); });
@ -74,6 +70,37 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
_topLeft = _layerEditorService.GetLayerPath(layer, true, true, true).Points[0]; _topLeft = _layerEditorService.GetLayerPath(layer, true, true, true).Points[0];
} }
#region Overrides of Screen
/// <inheritdoc />
protected override void OnInitialActivate()
{
ProfileEditorService.ProfileSelected += UpdateEventHandler;
ProfileEditorService.ProfileElementSelected += UpdateEventHandler;
ProfileEditorService.SelectedProfileElementUpdated += UpdateEventHandler;
ProfileEditorService.ProfilePreviewUpdated += UpdateEventHandler;
Update();
base.OnInitialActivate();
}
private void UpdateEventHandler(object sender, EventArgs e)
{
Update();
}
/// <inheritdoc />
protected override void OnClose()
{
ProfileEditorService.ProfileSelected -= UpdateEventHandler;
ProfileEditorService.ProfileElementSelected -= UpdateEventHandler;
ProfileEditorService.SelectedProfileElementUpdated -= UpdateEventHandler;
ProfileEditorService.ProfilePreviewUpdated -= UpdateEventHandler;
base.OnClose();
}
#endregion
#region Rotation #region Rotation
private bool _rotating; private bool _rotating;

View File

@ -5,6 +5,7 @@ using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using Artemis.Core; using Artemis.Core;
using Artemis.UI.Properties; using Artemis.UI.Properties;
using Artemis.UI.Screens.Shared;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
@ -13,7 +14,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
{ {
private Rect _dragRectangle; private Rect _dragRectangle;
public SelectionRemoveToolViewModel(ProfileViewModel profileViewModel, IProfileEditorService profileEditorService) : base(profileViewModel, profileEditorService) public SelectionRemoveToolViewModel(PanZoomViewModel panZoomViewModel, IProfileEditorService profileEditorService) : base(panZoomViewModel, profileEditorService)
{ {
using (MemoryStream stream = new(Resources.aero_pen_min)) using (MemoryStream stream = new(Resources.aero_pen_min))
{ {
@ -31,13 +32,11 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
{ {
base.MouseUp(sender, e); base.MouseUp(sender, e);
Point position = ProfileViewModel.PanZoomViewModel.GetRelativeMousePosition(sender, e); Point position = PanZoomViewModel.GetRelativeMousePosition(sender, e);
Rect selectedRect = new(MouseDownStartPosition, position); Rect selectedRect = new(MouseDownStartPosition, position);
// Get selected LEDs // Get selected LEDs
List<ArtemisLed> selectedLeds = ProfileViewModel.GetLedsInRectangle(selectedRect); List<ArtemisLed> selectedLeds = ProfileEditorService.GetLedsInRectangle(selectedRect);
ProfileViewModel.SelectedLeds.Clear();
ProfileViewModel.SelectedLeds.AddRange(selectedLeds);
// Apply the selection to the selected layer layer // Apply the selection to the selected layer layer
if (ProfileEditorService.SelectedProfileElement is Layer layer) if (ProfileEditorService.SelectedProfileElement is Layer layer)
@ -59,15 +58,8 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
return; return;
} }
Point position = ProfileViewModel.PanZoomViewModel.GetRelativeMousePosition(sender, e); Point position = PanZoomViewModel.GetRelativeMousePosition(sender, e);
Rect selectedRect = new(MouseDownStartPosition, position); Rect selectedRect = new(MouseDownStartPosition, position);
List<ArtemisLed> selectedLeds = ProfileViewModel.GetLedsInRectangle(selectedRect);
// Unless shift is held down, clear the current selection
if (!Keyboard.IsKeyDown(Key.LeftShift) && !Keyboard.IsKeyDown(Key.RightShift))
ProfileViewModel.SelectedLeds.Clear();
ProfileViewModel.SelectedLeds.AddRange(selectedLeds.Except(ProfileViewModel.SelectedLeds));
DragRectangle = selectedRect; DragRectangle = selectedRect;
} }
} }

View File

@ -7,6 +7,7 @@ using Artemis.Core;
using Artemis.Core.LayerBrushes; using Artemis.Core.LayerBrushes;
using Artemis.Core.Services; using Artemis.Core.Services;
using Artemis.UI.Properties; using Artemis.UI.Properties;
using Artemis.UI.Screens.Shared;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
@ -16,9 +17,8 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
private readonly ILayerBrushService _layerBrushService; private readonly ILayerBrushService _layerBrushService;
private Rect _dragRectangle; private Rect _dragRectangle;
public SelectionToolViewModel(ProfileViewModel profileViewModel, public SelectionToolViewModel(PanZoomViewModel panZoomViewModel, IProfileEditorService profileEditorService, ILayerBrushService layerBrushService)
IProfileEditorService profileEditorService, : base(panZoomViewModel, profileEditorService)
ILayerBrushService layerBrushService) : base(profileViewModel, profileEditorService)
{ {
_layerBrushService = layerBrushService; _layerBrushService = layerBrushService;
using (MemoryStream stream = new(Resources.aero_crosshair)) using (MemoryStream stream = new(Resources.aero_crosshair))
@ -37,11 +37,11 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
{ {
base.MouseUp(sender, e); base.MouseUp(sender, e);
Point position = ProfileViewModel.PanZoomViewModel.GetRelativeMousePosition(sender, e); Point position = PanZoomViewModel.GetRelativeMousePosition(sender, e);
Rect selectedRect = new(MouseDownStartPosition, position); Rect selectedRect = new(MouseDownStartPosition, position);
// Get selected LEDs // Get selected LEDs
List<ArtemisLed> selectedLeds = ProfileViewModel.GetLedsInRectangle(selectedRect); List<ArtemisLed> selectedLeds = ProfileEditorService.GetLedsInRectangle(selectedRect);
// Apply the selection to the selected layer layer // Apply the selection to the selected layer layer
if (ProfileEditorService.SelectedProfileElement is Layer layer) if (ProfileEditorService.SelectedProfileElement is Layer layer)
@ -77,14 +77,9 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
return; return;
} }
Point position = ProfileViewModel.PanZoomViewModel.GetRelativeMousePosition(sender, e); Point position = PanZoomViewModel.GetRelativeMousePosition(sender, e);
Rect selectedRect = new(MouseDownStartPosition, position); Rect selectedRect = new(MouseDownStartPosition, position);
List<ArtemisLed> selectedLeds = ProfileViewModel.GetLedsInRectangle(selectedRect); List<ArtemisLed> selectedLeds = ProfileEditorService.GetLedsInRectangle(selectedRect);
// Unless shift is held down, clear the current selection
if (!Keyboard.IsKeyDown(Key.LeftShift) && !Keyboard.IsKeyDown(Key.RightShift))
ProfileViewModel.SelectedLeds.Clear();
ProfileViewModel.SelectedLeds.AddRange(selectedLeds.Except(ProfileViewModel.SelectedLeds));
DragRectangle = selectedRect; DragRectangle = selectedRect;
} }

View File

@ -1,20 +1,21 @@
using System.Windows.Input; using System.Windows.Input;
using Artemis.UI.Screens.Shared;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
{ {
public class ViewpointMoveToolViewModel : VisualizationToolViewModel public class ViewpointMoveToolViewModel : VisualizationToolViewModel
{ {
public ViewpointMoveToolViewModel(ProfileViewModel profileViewModel, IProfileEditorService profileEditorService) : base(profileViewModel, profileEditorService) public ViewpointMoveToolViewModel(PanZoomViewModel panZoomViewModel, IProfileEditorService profileEditorService) : base(panZoomViewModel, profileEditorService)
{ {
Cursor = Cursors.Hand; Cursor = Cursors.Hand;
ProfileViewModel.PanZoomViewModel.LastPanPosition = null; PanZoomViewModel.LastPanPosition = null;
} }
public override void MouseMove(object sender, MouseEventArgs e) public override void MouseMove(object sender, MouseEventArgs e)
{ {
base.MouseMove(sender, e); base.MouseMove(sender, e);
ProfileViewModel.PanZoomViewModel.ProcessMouseMove(sender, e); PanZoomViewModel.ProcessMouseMove(sender, e);
} }
} }
} }

View File

@ -1,6 +1,9 @@
using System; using System;
using System.Collections.Generic;
using System.Windows; using System.Windows;
using System.Windows.Input; using System.Windows.Input;
using Artemis.Core;
using Artemis.UI.Screens.Shared;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
@ -11,18 +14,18 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
private bool _isMouseDown; private bool _isMouseDown;
private Point _mouseDownStartPosition; private Point _mouseDownStartPosition;
protected VisualizationToolViewModel(ProfileViewModel profileViewModel, IProfileEditorService profileEditorService) protected VisualizationToolViewModel(PanZoomViewModel panZoomViewModel, IProfileEditorService profileEditorService)
{ {
// Not relevant for visualization tools as they overlay the entire canvas // Not relevant for visualization tools as they overlay the entire canvas
X = 0; X = 0;
Y = 0; Y = 0;
ProfileViewModel = profileViewModel; PanZoomViewModel = panZoomViewModel;
ProfileEditorService = profileEditorService; ProfileEditorService = profileEditorService;
Cursor = Cursors.Arrow; Cursor = Cursors.Arrow;
} }
public ProfileViewModel ProfileViewModel { get; } public PanZoomViewModel PanZoomViewModel { get; }
public IProfileEditorService ProfileEditorService { get; } public IProfileEditorService ProfileEditorService { get; }
public Cursor Cursor public Cursor Cursor
@ -46,7 +49,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
public virtual void MouseDown(object sender, MouseButtonEventArgs e) public virtual void MouseDown(object sender, MouseButtonEventArgs e)
{ {
IsMouseDown = true; IsMouseDown = true;
MouseDownStartPosition = ProfileViewModel.PanZoomViewModel.GetRelativeMousePosition(sender, e); MouseDownStartPosition = PanZoomViewModel.GetRelativeMousePosition(sender, e);
} }
public virtual void MouseUp(object sender, MouseButtonEventArgs e) public virtual void MouseUp(object sender, MouseButtonEventArgs e)

View File

@ -64,7 +64,6 @@ namespace Artemis.UI.Screens
_builtInRegistrationService = builtInRegistrationService; _builtInRegistrationService = builtInRegistrationService;
_snackbarMessageQueue = snackbarMessageQueue; _snackbarMessageQueue = snackbarMessageQueue;
_sidebarViewModel = sidebarViewModel; _sidebarViewModel = sidebarViewModel;
_frameTimeUpdateTimer = new Timer(500); _frameTimeUpdateTimer = new Timer(500);
_colorScheme = _settingsService.GetSetting("UI.ColorScheme", ApplicationColorScheme.Automatic); _colorScheme = _settingsService.GetSetting("UI.ColorScheme", ApplicationColorScheme.Automatic);
@ -73,6 +72,8 @@ namespace Artemis.UI.Screens
_themeWatcher = new ThemeWatcher(); _themeWatcher = new ThemeWatcher();
ApplyColorSchemeSetting(); ApplyColorSchemeSetting();
_sidebarViewModel.ConductWith(this);
ActiveItem = sidebarViewModel.SelectedItem; ActiveItem = sidebarViewModel.SelectedItem;
ActiveItemReady = true; ActiveItemReady = true;
PinSidebar = _settingsService.GetSetting("UI.PinSidebar", false); PinSidebar = _settingsService.GetSetting("UI.PinSidebar", false);
@ -334,7 +335,6 @@ namespace Artemis.UI.Screens
GC.Collect(); GC.Collect();
}); });
base.OnClose(); base.OnClose();
} }

View File

@ -22,13 +22,13 @@ using Stylet;
namespace Artemis.UI.Screens.Sidebar namespace Artemis.UI.Screens.Sidebar
{ {
public sealed class SidebarViewModel : PropertyChangedBase, IHandle<RequestSelectSidebarItemEvent>, IDisposable public sealed class SidebarViewModel : Screen, IHandle<RequestSelectSidebarItemEvent>, IDisposable
{ {
private readonly Timer _activeModulesUpdateTimer; private readonly Timer _activeModulesUpdateTimer;
private readonly IKernel _kernel; private readonly IKernel _kernel;
private readonly ISettingsService _settingsService;
private readonly IModuleVmFactory _moduleVmFactory; private readonly IModuleVmFactory _moduleVmFactory;
private readonly IPluginManagementService _pluginManagementService; private readonly IPluginManagementService _pluginManagementService;
private readonly IModuleService _moduleService;
private string _activeModules; private string _activeModules;
private bool _isSidebarOpen; private bool _isSidebarOpen;
private IScreen _selectedItem; private IScreen _selectedItem;
@ -38,9 +38,9 @@ namespace Artemis.UI.Screens.Sidebar
public SidebarViewModel(IKernel kernel, ISettingsService settingsService, IEventAggregator eventAggregator, IModuleVmFactory moduleVmFactory, IPluginManagementService pluginManagementService, IModuleService moduleService) public SidebarViewModel(IKernel kernel, ISettingsService settingsService, IEventAggregator eventAggregator, IModuleVmFactory moduleVmFactory, IPluginManagementService pluginManagementService, IModuleService moduleService)
{ {
_kernel = kernel; _kernel = kernel;
_settingsService = settingsService;
_moduleVmFactory = moduleVmFactory; _moduleVmFactory = moduleVmFactory;
_pluginManagementService = pluginManagementService; _pluginManagementService = pluginManagementService;
_moduleService = moduleService;
SidebarModules = new Dictionary<INavigationItem, Module>(); SidebarModules = new Dictionary<INavigationItem, Module>();
SidebarItems = new BindableCollection<INavigationItem>(); SidebarItems = new BindableCollection<INavigationItem>();
@ -48,14 +48,6 @@ namespace Artemis.UI.Screens.Sidebar
PinSidebar.AutoSave = true; PinSidebar.AutoSave = true;
_activeModulesUpdateTimer = new Timer(1000); _activeModulesUpdateTimer = new Timer(1000);
_activeModulesUpdateTimer.Start();
_activeModulesUpdateTimer.Elapsed += ActiveModulesUpdateTimerOnElapsed;
_pluginManagementService.PluginFeatureEnabled += OnFeatureEnabled;
_pluginManagementService.PluginFeatureDisabled += OnFeatureDisabled;
moduleService.ModulePriorityUpdated += OnModulePriorityUpdated;
SetupSidebar();
eventAggregator.Subscribe(this); eventAggregator.Subscribe(this);
} }
@ -250,5 +242,36 @@ namespace Artemis.UI.Screens.Sidebar
} }
#endregion #endregion
#region Overrides of Screen
/// <inheritdoc />
protected override void OnInitialActivate()
{
_activeModulesUpdateTimer.Start();
_activeModulesUpdateTimer.Elapsed += ActiveModulesUpdateTimerOnElapsed;
_pluginManagementService.PluginFeatureEnabled += OnFeatureEnabled;
_pluginManagementService.PluginFeatureDisabled += OnFeatureDisabled;
_moduleService.ModulePriorityUpdated += OnModulePriorityUpdated;
SetupSidebar();
base.OnInitialActivate();
}
/// <inheritdoc />
protected override void OnClose()
{
_activeModulesUpdateTimer.Stop();
_activeModulesUpdateTimer.Elapsed -= ActiveModulesUpdateTimerOnElapsed;
_pluginManagementService.PluginFeatureEnabled -= OnFeatureEnabled;
_pluginManagementService.PluginFeatureDisabled -= OnFeatureDisabled;
_moduleService.ModulePriorityUpdated -= OnModulePriorityUpdated;
base.OnClose();
}
#endregion
} }
} }