diff --git a/src/Artemis.Core/Artemis.Core.csproj b/src/Artemis.Core/Artemis.Core.csproj index 76547bbd5..afb0d5028 100644 --- a/src/Artemis.Core/Artemis.Core.csproj +++ b/src/Artemis.Core/Artemis.Core.csproj @@ -34,7 +34,6 @@ - diff --git a/src/Artemis.Core/Models/Profile/Conditions/Abstract/DisplayConditionPart.cs b/src/Artemis.Core/Models/Profile/Conditions/Abstract/DisplayConditionPart.cs index c862d90e1..7c1baa735 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/Abstract/DisplayConditionPart.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/Abstract/DisplayConditionPart.cs @@ -32,5 +32,7 @@ namespace Artemis.Core.Models.Profile.Conditions.Abstract _children.Remove(displayConditionPart); } } + + public abstract void ApplyToEntity(); } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionGroup.cs b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionGroup.cs index 6249df7fe..a2cb69f9e 100644 --- a/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionGroup.cs +++ b/src/Artemis.Core/Models/Profile/Conditions/DisplayConditionGroup.cs @@ -5,6 +5,12 @@ namespace Artemis.Core.Models.Profile.Conditions public class DisplayConditionGroup : DisplayConditionPart { public BooleanOperator BooleanOperator { get; set; } + + public override void ApplyToEntity() + { + foreach (var child in Children) + child.ApplyToEntity(); + } } public enum BooleanOperator diff --git a/src/Artemis.Core/Models/Profile/Folder.cs b/src/Artemis.Core/Models/Profile/Folder.cs index 984414d13..2d0f58c01 100644 --- a/src/Artemis.Core/Models/Profile/Folder.cs +++ b/src/Artemis.Core/Models/Profile/Folder.cs @@ -7,7 +7,7 @@ using SkiaSharp; namespace Artemis.Core.Models.Profile { - public sealed class Folder : EffectProfileElement + public sealed class Folder : RenderProfileElement { private SKBitmap _folderBitmap; @@ -159,7 +159,7 @@ namespace Artemis.Core.Models.Profile var path = new SKPath {FillType = SKPathFillType.Winding}; foreach (var child in Children) { - if (child is EffectProfileElement effectChild && effectChild.Path != null) + if (child is RenderProfileElement effectChild && effectChild.Path != null) path.AddPath(effectChild.Path); } @@ -182,10 +182,13 @@ namespace Artemis.Core.Models.Profile FolderEntity.Enabled = Enabled; FolderEntity.ProfileId = Profile.EntityId; + FolderEntity.ExpandedPropertyGroups.Clear(); + FolderEntity.ExpandedPropertyGroups.AddRange(_expandedPropertyGroups); ApplyLayerEffectsToEntity(); - // TODO: conditions + // Conditions + DisplayConditionGroup?.ApplyToEntity(); } #region Events diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs index ea58f3550..ce23f175d 100644 --- a/src/Artemis.Core/Models/Profile/Layer.cs +++ b/src/Artemis.Core/Models/Profile/Layer.cs @@ -21,9 +21,8 @@ namespace Artemis.Core.Models.Profile /// Represents a layer on a profile. To create new layers use the by injecting /// into your code /// - public sealed class Layer : EffectProfileElement + public sealed class Layer : RenderProfileElement { - private DisplayConditionGroup _displayConditionGroup; private LayerGeneralProperties _general; private SKBitmap _layerBitmap; private BaseLayerBrush _layerBrush; @@ -117,14 +116,7 @@ namespace Artemis.Core.Models.Profile internal set => SetAndNotify(ref _layerBrush, value); } - /// - /// Gets or sets the root display condition group - /// - public DisplayConditionGroup DisplayConditionGroup - { - get => _displayConditionGroup; - set => SetAndNotify(ref _displayConditionGroup, value); - } + public override string ToString() { @@ -164,8 +156,8 @@ namespace Artemis.Core.Models.Profile LayerEntity.Leds.Add(ledEntity); } - // Conditions TODO - LayerEntity.Conditions.Clear(); + // Conditions + DisplayConditionGroup?.ApplyToEntity(); } #endregion diff --git a/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs b/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs index 22e232ed0..7051cce17 100644 --- a/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs +++ b/src/Artemis.Core/Models/Profile/LayerProperties/BaseLayerProperty.cs @@ -20,7 +20,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties /// /// Gets the profile element (such as layer or folder) this effect is applied to /// - public PropertiesProfileElement ProfileElement { get; internal set; } + public RenderProfileElement ProfileElement { get; internal set; } /// /// The parent group of this layer property, set after construction diff --git a/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs b/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs index 76e45c766..87a6b6a33 100644 --- a/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs +++ b/src/Artemis.Core/Models/Profile/LayerPropertyGroup.cs @@ -31,7 +31,7 @@ namespace Artemis.Core.Models.Profile /// /// Gets the profile element (such as layer or folder) this effect is applied to /// - public PropertiesProfileElement ProfileElement { get; internal set; } + public RenderProfileElement ProfileElement { get; internal set; } /// /// The path of this property group @@ -129,7 +129,7 @@ namespace Artemis.Core.Models.Profile PropertyGroupInitialized?.Invoke(this, EventArgs.Empty); } - internal void InitializeProperties(ILayerService layerService, PropertiesProfileElement profileElement, [NotNull] string path) + internal void InitializeProperties(ILayerService layerService, RenderProfileElement profileElement, [NotNull] string path) { if (path == null) throw new ArgumentNullException(nameof(path)); @@ -236,7 +236,7 @@ namespace Artemis.Core.Models.Profile OnPropertyGroupOverriding(new PropertyGroupUpdatingEventArgs(overrideTime)); } - private void InitializeProperty(PropertiesProfileElement profileElement, string path, BaseLayerProperty instance) + private void InitializeProperty(RenderProfileElement profileElement, string path, BaseLayerProperty instance) { Guid pluginGuid; if (IsCorePropertyGroup || instance.IsCoreProperty) diff --git a/src/Artemis.Core/Models/Profile/PropertiesProfileElement.cs b/src/Artemis.Core/Models/Profile/PropertiesProfileElement.cs index 184e2d4c7..4fc04ac97 100644 --- a/src/Artemis.Core/Models/Profile/PropertiesProfileElement.cs +++ b/src/Artemis.Core/Models/Profile/PropertiesProfileElement.cs @@ -6,52 +6,6 @@ namespace Artemis.Core.Models.Profile { public abstract class PropertiesProfileElement : ProfileElement { - private SKPath _path; - internal abstract PropertiesEntity PropertiesEntity { get; } - - /// - /// Gets the path containing all the LEDs this entity is applied to, any rendering outside the entity Path is - /// clipped. - /// - public SKPath Path - { - get => _path; - protected set - { - SetAndNotify(ref _path, value); - // I can't really be sure about the performance impact of calling Bounds often but - // SkiaSharp calls SkiaApi.sk_path_get_bounds (Handle, &rect); which sounds expensive - Bounds = value?.Bounds ?? SKRect.Empty; - } - } - - /// - /// The bounds of this entity - /// - public SKRect Bounds - { - get => _bounds; - private set => SetAndNotify(ref _bounds, value); - } - - #region Property group expansion - - protected List _expandedPropertyGroups; - private SKRect _bounds; - - public bool IsPropertyGroupExpanded(LayerPropertyGroup layerPropertyGroup) - { - return _expandedPropertyGroups.Contains(layerPropertyGroup.Path); - } - - public void SetPropertyGroupExpanded(LayerPropertyGroup layerPropertyGroup, bool expanded) - { - if (!expanded && IsPropertyGroupExpanded(layerPropertyGroup)) - _expandedPropertyGroups.Remove(layerPropertyGroup.Path); - else if (expanded && !IsPropertyGroupExpanded(layerPropertyGroup)) - _expandedPropertyGroups.Add(layerPropertyGroup.Path); - } - - #endregion + } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/EffectProfileElement.cs b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs similarity index 54% rename from src/Artemis.Core/Models/Profile/EffectProfileElement.cs rename to src/Artemis.Core/Models/Profile/RenderProfileElement.cs index 93e0e7ab6..83bc2289e 100644 --- a/src/Artemis.Core/Models/Profile/EffectProfileElement.cs +++ b/src/Artemis.Core/Models/Profile/RenderProfileElement.cs @@ -3,13 +3,69 @@ using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using Artemis.Core.Annotations; +using Artemis.Core.Models.Profile.Conditions; using Artemis.Core.Plugins.LayerEffect.Abstract; using Artemis.Storage.Entities.Profile; +using SkiaSharp; namespace Artemis.Core.Models.Profile { - public abstract class EffectProfileElement : PropertiesProfileElement + public abstract class RenderProfileElement : ProfileElement { + #region Properties + + private SKPath _path; + internal abstract PropertiesEntity PropertiesEntity { get; } + + /// + /// Gets the path containing all the LEDs this entity is applied to, any rendering outside the entity Path is + /// clipped. + /// + public SKPath Path + { + get => _path; + protected set + { + SetAndNotify(ref _path, value); + // I can't really be sure about the performance impact of calling Bounds often but + // SkiaSharp calls SkiaApi.sk_path_get_bounds (Handle, &rect); which sounds expensive + Bounds = value?.Bounds ?? SKRect.Empty; + } + } + + /// + /// The bounds of this entity + /// + public SKRect Bounds + { + get => _bounds; + private set => SetAndNotify(ref _bounds, value); + } + + #region Property group expansion + + protected List _expandedPropertyGroups; + private SKRect _bounds; + + public bool IsPropertyGroupExpanded(LayerPropertyGroup layerPropertyGroup) + { + return _expandedPropertyGroups.Contains(layerPropertyGroup.Path); + } + + public void SetPropertyGroupExpanded(LayerPropertyGroup layerPropertyGroup, bool expanded) + { + if (!expanded && IsPropertyGroupExpanded(layerPropertyGroup)) + _expandedPropertyGroups.Remove(layerPropertyGroup.Path); + else if (expanded && !IsPropertyGroupExpanded(layerPropertyGroup)) + _expandedPropertyGroups.Add(layerPropertyGroup.Path); + } + + #endregion + + #endregion + + #region Effects + protected List _layerEffects; internal abstract EffectsEntity EffectsEntity { get; } @@ -71,6 +127,23 @@ namespace Artemis.Core.Models.Profile effect.Dispose(); } + #endregion + + #region Conditions + + private DisplayConditionGroup _displayConditionGroup; + + /// + /// Gets or sets the root display condition group + /// + public DisplayConditionGroup DisplayConditionGroup + { + get => _displayConditionGroup; + set => SetAndNotify(ref _displayConditionGroup, value); + } + + #endregion + #region Events public event EventHandler LayerEffectsUpdated; diff --git a/src/Artemis.Core/Plugins/LayerEffect/Abstract/BaseLayerEffect.cs b/src/Artemis.Core/Plugins/LayerEffect/Abstract/BaseLayerEffect.cs index c93a290cb..d7488f1ce 100644 --- a/src/Artemis.Core/Plugins/LayerEffect/Abstract/BaseLayerEffect.cs +++ b/src/Artemis.Core/Plugins/LayerEffect/Abstract/BaseLayerEffect.cs @@ -14,7 +14,7 @@ namespace Artemis.Core.Plugins.LayerEffect.Abstract public abstract class BaseLayerEffect : PropertyChangedBase, IDisposable { private Guid _entityId; - private EffectProfileElement _profileElement; + private RenderProfileElement _profileElement; private string _name; private bool _enabled; private bool _hasBeenRenamed; @@ -33,7 +33,7 @@ namespace Artemis.Core.Plugins.LayerEffect.Abstract /// /// Gets the profile element (such as layer or folder) this effect is applied to /// - public EffectProfileElement ProfileElement + public RenderProfileElement ProfileElement { get => _profileElement; internal set => SetAndNotify(ref _profileElement, value); diff --git a/src/Artemis.Core/Services/Interfaces/ILayerService.cs b/src/Artemis.Core/Services/Interfaces/ILayerService.cs index 69d281977..43fe7a6fd 100644 --- a/src/Artemis.Core/Services/Interfaces/ILayerService.cs +++ b/src/Artemis.Core/Services/Interfaces/ILayerService.cs @@ -42,17 +42,17 @@ namespace Artemis.Core.Services.Interfaces /// Instantiates and adds the described by the provided /// to the . /// - /// The layer/folder to instantiate the effect for - void InstantiateLayerEffects(EffectProfileElement effectProfileElement); + /// The layer/folder to instantiate the effect for + void InstantiateLayerEffects(RenderProfileElement renderProfileElement); /// /// Adds the described by the provided to the /// . /// - /// The layer/folder to instantiate the effect for + /// The layer/folder to instantiate the effect for /// /// - BaseLayerEffect AddLayerEffect(EffectProfileElement effectProfileElement, LayerEffectDescriptor layerEffectDescriptor); + BaseLayerEffect AddLayerEffect(RenderProfileElement renderProfileElement, LayerEffectDescriptor layerEffectDescriptor); void RemoveLayerEffect(BaseLayerEffect layerEffect); } diff --git a/src/Artemis.Core/Services/LayerService.cs b/src/Artemis.Core/Services/LayerService.cs index 704250729..d2491f9b4 100644 --- a/src/Artemis.Core/Services/LayerService.cs +++ b/src/Artemis.Core/Services/LayerService.cs @@ -20,7 +20,7 @@ namespace Artemis.Core.Services private readonly ILogger _logger; private readonly IPluginService _pluginService; - public LayerService(IKernel kernel, ILogger logger, IPluginService pluginService) + public LayerService(IKernel kernel, ILogger logger, IPluginService pluginService, IDataModelService dataModelService) { _kernel = kernel; _logger = logger; @@ -39,7 +39,6 @@ namespace Artemis.Core.Services // With the properties loaded, the layer brush and effect can be instantiated InstantiateLayerBrush(layer); InstantiateLayerEffects(layer); - return layer; } @@ -85,21 +84,21 @@ namespace Artemis.Core.Services return brush; } - public BaseLayerEffect AddLayerEffect(EffectProfileElement effectElement, LayerEffectDescriptor layerEffectDescriptor) + public BaseLayerEffect AddLayerEffect(RenderProfileElement renderElement, LayerEffectDescriptor layerEffectDescriptor) { // Create the effect with dependency injection var effect = (BaseLayerEffect) _kernel.Get(layerEffectDescriptor.LayerEffectType); - effect.ProfileElement = effectElement; + effect.ProfileElement = renderElement; effect.EntityId = Guid.NewGuid(); effect.Enabled = true; - effect.Order = effectElement.LayerEffects.Count + 1; + effect.Order = renderElement.LayerEffects.Count + 1; effect.Descriptor = layerEffectDescriptor; effect.Initialize(this); effect.Update(0); - effectElement.AddLayerEffect(effect); + renderElement.AddLayerEffect(effect); _logger.Debug("Added layer effect with root path {rootPath}", effect.PropertyRootPath); return effect; } @@ -109,16 +108,16 @@ namespace Artemis.Core.Services layerEffect.ProfileElement.RemoveLayerEffect(layerEffect); } - public void InstantiateLayerEffects(EffectProfileElement effectElement) + public void InstantiateLayerEffects(RenderProfileElement renderElement) { var layerEffectProviders = _pluginService.GetPluginsOfType(); var descriptors = layerEffectProviders.SelectMany(l => l.LayerEffectDescriptors).ToList(); - var entities = effectElement.EffectsEntity.LayerEffects.OrderByDescending(e => e.Order).ToList(); + var entities = renderElement.EffectsEntity.LayerEffects.OrderByDescending(e => e.Order).ToList(); foreach (var layerEffectEntity in entities) { // Skip effects already on the element - if (effectElement.LayerEffects.Any(e => e.EntityId == layerEffectEntity.Id)) + if (renderElement.LayerEffects.Any(e => e.EntityId == layerEffectEntity.Id)) continue; // Get a matching descriptor @@ -130,7 +129,7 @@ namespace Artemis.Core.Services // Create the effect with dependency injection var effect = (BaseLayerEffect) _kernel.Get(descriptor.LayerEffectType); - effect.ProfileElement = effectElement; + effect.ProfileElement = renderElement; effect.EntityId = layerEffectEntity.Id; effect.Order = layerEffectEntity.Order; effect.Name = layerEffectEntity.Name; @@ -140,9 +139,14 @@ namespace Artemis.Core.Services effect.Initialize(this); effect.Update(0); - effectElement.AddLayerEffect(effect); + renderElement.AddLayerEffect(effect); _logger.Debug("Instantiated layer effect with root path {rootPath}", effect.PropertyRootPath); } } + + public void InstantiateDisplayConditions(RenderProfileElement renderElement) + { + + } } } \ No newline at end of file diff --git a/src/Artemis.Storage/Entities/Profile/PropertiesEntity.cs b/src/Artemis.Storage/Entities/Profile/PropertiesEntity.cs index 3f2baa9a8..af9f308a0 100644 --- a/src/Artemis.Storage/Entities/Profile/PropertiesEntity.cs +++ b/src/Artemis.Storage/Entities/Profile/PropertiesEntity.cs @@ -4,7 +4,6 @@ namespace Artemis.Storage.Entities.Profile { public abstract class PropertiesEntity { - public List Conditions { get; set; } public List PropertyEntities { get; set; } public List ExpandedPropertyGroups { get; set; } } diff --git a/src/Artemis.UI.Shared/Controls/ColorPicker.xaml b/src/Artemis.UI.Shared/Controls/ColorPicker.xaml index 07968179f..26b21db45 100644 --- a/src/Artemis.UI.Shared/Controls/ColorPicker.xaml +++ b/src/Artemis.UI.Shared/Controls/ColorPicker.xaml @@ -90,7 +90,7 @@ diff --git a/src/Artemis.UI.Shared/Events/ProfileElementEventArgs.cs b/src/Artemis.UI.Shared/Events/ProfileElementEventArgs.cs deleted file mode 100644 index d4909cc2e..000000000 --- a/src/Artemis.UI.Shared/Events/ProfileElementEventArgs.cs +++ /dev/null @@ -1,22 +0,0 @@ -using System; -using Artemis.Core.Models.Profile; - -namespace Artemis.UI.Shared.Events -{ - public class ProfileElementEventArgs : EventArgs - { - public ProfileElementEventArgs(ProfileElement profileElement) - { - ProfileElement = profileElement; - } - - public ProfileElementEventArgs(ProfileElement profileElement, ProfileElement previousProfileElement) - { - ProfileElement = profileElement; - PreviousProfileElement = previousProfileElement; - } - - public ProfileElement ProfileElement { get; } - public ProfileElement PreviousProfileElement { get; } - } -} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Events/ProfileEventArgs.cs b/src/Artemis.UI.Shared/Events/ProfileEventArgs.cs new file mode 100644 index 000000000..c686259b5 --- /dev/null +++ b/src/Artemis.UI.Shared/Events/ProfileEventArgs.cs @@ -0,0 +1,22 @@ +using System; +using Artemis.Core.Models.Profile; + +namespace Artemis.UI.Shared.Events +{ + public class ProfileEventArgs : EventArgs + { + public ProfileEventArgs(Profile profile) + { + Profile = profile; + } + + public ProfileEventArgs(Profile profile, Profile previousProfile) + { + Profile = profile; + PreviousProfile = previousProfile; + } + + public Profile Profile { get; } + public Profile PreviousProfile { get; } + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Events/RenderProfileElementEventArgs.cs b/src/Artemis.UI.Shared/Events/RenderProfileElementEventArgs.cs new file mode 100644 index 000000000..e6b027987 --- /dev/null +++ b/src/Artemis.UI.Shared/Events/RenderProfileElementEventArgs.cs @@ -0,0 +1,22 @@ +using System; +using Artemis.Core.Models.Profile; + +namespace Artemis.UI.Shared.Events +{ + public class RenderProfileElementEventArgs : EventArgs + { + public RenderProfileElementEventArgs(RenderProfileElement renderProfileElement) + { + RenderProfileElement = renderProfileElement; + } + + public RenderProfileElementEventArgs(RenderProfileElement renderProfileElement, RenderProfileElement previousRenderProfileElement) + { + RenderProfileElement = renderProfileElement; + PreviousRenderProfileElement = previousRenderProfileElement; + } + + public RenderProfileElement RenderProfileElement { get; } + public RenderProfileElement PreviousRenderProfileElement { get; } + } +} \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Services/Interfaces/IProfileEditorService.cs b/src/Artemis.UI.Shared/Services/Interfaces/IProfileEditorService.cs index 5633ecdb6..4738fe07b 100644 --- a/src/Artemis.UI.Shared/Services/Interfaces/IProfileEditorService.cs +++ b/src/Artemis.UI.Shared/Services/Interfaces/IProfileEditorService.cs @@ -12,7 +12,7 @@ namespace Artemis.UI.Shared.Services.Interfaces public interface IProfileEditorService : IArtemisSharedUIService { Profile SelectedProfile { get; } - ProfileElement SelectedProfileElement { get; } + RenderProfileElement SelectedProfileElement { get; } TimeSpan CurrentTime { get; set; } int PixelsPerSecond { get; set; } IReadOnlyList RegisteredPropertyEditors { get; } @@ -20,7 +20,7 @@ namespace Artemis.UI.Shared.Services.Interfaces void ChangeSelectedProfile(Profile profile); void UpdateSelectedProfile(); - void ChangeSelectedProfileElement(ProfileElement profileElement); + void ChangeSelectedProfileElement(RenderProfileElement profileElement); void UpdateSelectedProfileElement(); void UpdateProfilePreview(); void UndoUpdateProfile(ProfileModule module); @@ -32,22 +32,22 @@ namespace Artemis.UI.Shared.Services.Interfaces /// /// Occurs when a new profile is selected /// - event EventHandler ProfileSelected; + event EventHandler ProfileSelected; /// /// Occurs then the currently selected profile is updated /// - event EventHandler SelectedProfileUpdated; + event EventHandler SelectedProfileUpdated; /// /// Occurs when a new profile element is selected /// - event EventHandler ProfileElementSelected; + event EventHandler ProfileElementSelected; /// /// Occurs when the currently selected profile element is updated /// - event EventHandler SelectedProfileElementUpdated; + event EventHandler SelectedProfileElementUpdated; /// /// Occurs when the current editor time is changed diff --git a/src/Artemis.UI.Shared/Services/ProfileEditorService.cs b/src/Artemis.UI.Shared/Services/ProfileEditorService.cs index 18347f427..34384bddf 100644 --- a/src/Artemis.UI.Shared/Services/ProfileEditorService.cs +++ b/src/Artemis.UI.Shared/Services/ProfileEditorService.cs @@ -11,6 +11,7 @@ using Artemis.UI.Shared.Events; using Artemis.UI.Shared.PropertyInput; using Artemis.UI.Shared.Services.Interfaces; using Ninject; +using Serilog; namespace Artemis.UI.Shared.Services { @@ -18,15 +19,17 @@ namespace Artemis.UI.Shared.Services { private readonly ICoreService _coreService; private readonly IProfileService _profileService; + private readonly ILogger _logger; private readonly List _registeredPropertyEditors; private TimeSpan _currentTime; private TimeSpan _lastUpdateTime; private int _pixelsPerSecond; - public ProfileEditorService(ICoreService coreService, IProfileService profileService, IKernel kernel) + public ProfileEditorService(ICoreService coreService, IProfileService profileService, IKernel kernel, ILogger logger) { _coreService = coreService; _profileService = profileService; + _logger = logger; _registeredPropertyEditors = new List(); Kernel = kernel; @@ -36,7 +39,7 @@ namespace Artemis.UI.Shared.Services public IKernel Kernel { get; } public IReadOnlyList RegisteredPropertyEditors => _registeredPropertyEditors.AsReadOnly(); public Profile SelectedProfile { get; private set; } - public ProfileElement SelectedProfileElement { get; private set; } + public RenderProfileElement SelectedProfileElement { get; private set; } public TimeSpan CurrentTime { @@ -63,9 +66,13 @@ namespace Artemis.UI.Shared.Services public void ChangeSelectedProfile(Profile profile) { + if (SelectedProfile == profile) + return; + + _logger.Verbose("ChangeSelectedProfile {profile}", profile); ChangeSelectedProfileElement(null); - var profileElementEvent = new ProfileElementEventArgs(profile, SelectedProfile); + var profileElementEvent = new ProfileEventArgs(profile, SelectedProfile); SelectedProfile = profile; UpdateProfilePreview(); OnSelectedProfileChanged(profileElementEvent); @@ -73,23 +80,29 @@ namespace Artemis.UI.Shared.Services public void UpdateSelectedProfile() { + _logger.Verbose("UpdateSelectedProfile {profile}", SelectedProfile); _profileService.UpdateProfile(SelectedProfile, true); UpdateProfilePreview(); - OnSelectedProfileElementUpdated(new ProfileElementEventArgs(SelectedProfile)); + OnSelectedProfileChanged(new ProfileEventArgs(SelectedProfile)); } - public void ChangeSelectedProfileElement(ProfileElement profileElement) + public void ChangeSelectedProfileElement(RenderProfileElement profileElement) { - var profileElementEvent = new ProfileElementEventArgs(profileElement, SelectedProfileElement); + if (SelectedProfileElement == profileElement) + return; + + _logger.Verbose("ChangeSelectedProfileElement {profile}", profileElement); + var profileElementEvent = new RenderProfileElementEventArgs(profileElement, SelectedProfileElement); SelectedProfileElement = profileElement; OnSelectedProfileElementChanged(profileElementEvent); } public void UpdateSelectedProfileElement() { + _logger.Verbose("UpdateSelectedProfileElement {profile}", SelectedProfileElement); _profileService.UpdateProfile(SelectedProfile, true); UpdateProfilePreview(); - OnSelectedProfileElementUpdated(new ProfileElementEventArgs(SelectedProfileElement)); + OnSelectedProfileElementUpdated(new RenderProfileElementEventArgs(SelectedProfileElement)); } public void UpdateProfilePreview() @@ -122,11 +135,11 @@ namespace Artemis.UI.Shared.Services if (!undid) return; - OnSelectedProfileChanged(new ProfileElementEventArgs(SelectedProfile, SelectedProfile)); + OnSelectedProfileChanged(new ProfileEventArgs(SelectedProfile, SelectedProfile)); if (SelectedProfileElement != null) { - var elements = SelectedProfile.GetAllLayers().Cast().ToList(); + var elements = SelectedProfile.GetAllLayers().Cast().ToList(); elements.AddRange(SelectedProfile.GetAllFolders()); var element = elements.FirstOrDefault(l => l.EntityId == SelectedProfileElement.EntityId); ChangeSelectedProfileElement(element); @@ -141,11 +154,11 @@ namespace Artemis.UI.Shared.Services if (!redid) return; - OnSelectedProfileChanged(new ProfileElementEventArgs(SelectedProfile, SelectedProfile)); + OnSelectedProfileChanged(new ProfileEventArgs(SelectedProfile, SelectedProfile)); if (SelectedProfileElement != null) { - var elements = SelectedProfile.GetAllLayers().Cast().ToList(); + var elements = SelectedProfile.GetAllLayers().Cast().ToList(); elements.AddRange(SelectedProfile.GetAllFolders()); var element = elements.FirstOrDefault(l => l.EntityId == SelectedProfileElement.EntityId); ChangeSelectedProfileElement(element); @@ -194,10 +207,10 @@ namespace Artemis.UI.Shared.Services return (Module) SelectedProfile?.PluginInfo.Instance; } - public event EventHandler ProfileSelected; - public event EventHandler SelectedProfileUpdated; - public event EventHandler ProfileElementSelected; - public event EventHandler SelectedProfileElementUpdated; + public event EventHandler ProfileSelected; + public event EventHandler SelectedProfileUpdated; + public event EventHandler ProfileElementSelected; + public event EventHandler SelectedProfileElementUpdated; public event EventHandler CurrentTimeChanged; public event EventHandler PixelsPerSecondChanged; public event EventHandler ProfilePreviewUpdated; @@ -212,22 +225,22 @@ namespace Artemis.UI.Shared.Services _coreService.PluginUpdatingDisabled = false; } - protected virtual void OnSelectedProfileChanged(ProfileElementEventArgs e) + protected virtual void OnSelectedProfileChanged(ProfileEventArgs e) { ProfileSelected?.Invoke(this, e); } - protected virtual void OnSelectedProfileUpdated(ProfileElementEventArgs e) + protected virtual void OnSelectedProfileUpdated(ProfileEventArgs e) { SelectedProfileUpdated?.Invoke(this, e); } - protected virtual void OnSelectedProfileElementChanged(ProfileElementEventArgs e) + protected virtual void OnSelectedProfileElementChanged(RenderProfileElementEventArgs e) { ProfileElementSelected?.Invoke(this, e); } - protected virtual void OnSelectedProfileElementUpdated(ProfileElementEventArgs e) + protected virtual void OnSelectedProfileElementUpdated(RenderProfileElementEventArgs e) { SelectedProfileElementUpdated?.Invoke(this, e); } diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj index 7f31320f3..2142d0508 100644 --- a/src/Artemis.UI/Artemis.UI.csproj +++ b/src/Artemis.UI/Artemis.UI.csproj @@ -123,7 +123,6 @@ - diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs index dfd94f012..70ac868fd 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs @@ -1,5 +1,4 @@ -using Artemis.Core.Models.Profile; -using Artemis.Core.Models.Profile.Conditions; +using Artemis.Core.Models.Profile.Conditions; using Artemis.UI.Ninject.Factories; using Artemis.UI.Shared.Events; using Artemis.UI.Shared.Services.Interfaces; @@ -23,20 +22,21 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions set => SetAndNotify(ref _rootGroup, value); } - private void ProfileEditorServiceOnProfileElementSelected(object sender, ProfileElementEventArgs e) + private void ProfileEditorServiceOnProfileElementSelected(object sender, RenderProfileElementEventArgs e) { - if (e.ProfileElement is Layer layer) + if (e.RenderProfileElement == null) { - // Ensure the layer has a root display condition group - if (layer.DisplayConditionGroup == null) - layer.DisplayConditionGroup = new DisplayConditionGroup(); - - RootGroup = _displayConditionsVmFactory.DisplayConditionGroupViewModel(layer.DisplayConditionGroup, null); - RootGroup.IsRootGroup = true; - RootGroup.Update(); - } - else RootGroup = null; + return; + } + + // Ensure the layer has a root display condition group + if (e.RenderProfileElement.DisplayConditionGroup == null) + e.RenderProfileElement.DisplayConditionGroup = new DisplayConditionGroup(); + + RootGroup = _displayConditionsVmFactory.DisplayConditionGroupViewModel(e.RenderProfileElement.DisplayConditionGroup, null); + RootGroup.IsRootGroup = true; + RootGroup.Update(); } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerEffects/EffectsViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerEffects/EffectsViewModel.cs index 07d2392a3..72cca788a 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerEffects/EffectsViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerEffects/EffectsViewModel.cs @@ -56,11 +56,11 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.LayerEffects private void HandleSelectedLayerEffectChanged(object sender, PropertyChangedEventArgs e) { - EffectProfileElement effectElement; + RenderProfileElement renderElement; if (LayerPropertiesViewModel.SelectedLayer != null) - effectElement = LayerPropertiesViewModel.SelectedLayer; + renderElement = LayerPropertiesViewModel.SelectedLayer; else if (LayerPropertiesViewModel.SelectedFolder != null) - effectElement = LayerPropertiesViewModel.SelectedFolder; + renderElement = LayerPropertiesViewModel.SelectedFolder; else return; @@ -70,7 +70,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.LayerEffects Execute.PostToUIThread(async () => { await Task.Delay(500); - _layerService.AddLayerEffect(effectElement, SelectedLayerEffectDescriptor); + _layerService.AddLayerEffect(renderElement, SelectedLayerEffectDescriptor); _profileEditorService.UpdateSelectedProfileElement(); }); } diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs index af491d14e..8cc81045e 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs @@ -29,7 +29,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties private LayerPropertyGroupViewModel _brushPropertyGroup; private bool _repeatAfterLastKeyframe; private int _propertyTreeIndex; - private PropertiesProfileElement _selectedPropertiesElement; + private RenderProfileElement _selectedProfileElement; private BindableCollection _layerPropertyGroups; private TreeViewModel _treeViewModel; private EffectsViewModel _effectsViewModel; @@ -86,19 +86,19 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties public bool PropertyTreeVisible => PropertyTreeIndex == 0; - public PropertiesProfileElement SelectedPropertiesElement + public RenderProfileElement SelectedProfileElement { - get => _selectedPropertiesElement; + get => _selectedProfileElement; set { - if (!SetAndNotify(ref _selectedPropertiesElement, value)) return; + if (!SetAndNotify(ref _selectedProfileElement, value)) return; NotifyOfPropertyChange(nameof(SelectedLayer)); NotifyOfPropertyChange(nameof(SelectedFolder)); } } - public Layer SelectedLayer => SelectedPropertiesElement as Layer; - public Folder SelectedFolder => SelectedPropertiesElement as Folder; + public Layer SelectedLayer => SelectedProfileElement as Layer; + public Folder SelectedFolder => SelectedProfileElement as Folder; public BindableCollection LayerPropertyGroups { @@ -126,8 +126,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties protected override void OnInitialActivate() { - if (ProfileEditorService.SelectedProfileElement is PropertiesProfileElement propertiesElement) - PopulateProperties(propertiesElement); + PopulateProperties(ProfileEditorService.SelectedProfileElement); ProfileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected; ProfileEditorService.CurrentTimeChanged += ProfileEditorServiceOnCurrentTimeChanged; @@ -146,12 +145,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties base.OnClose(); } - protected override void OnActivate() - { - PopulateProperties(ProfileEditorService.SelectedProfileElement as PropertiesProfileElement); - base.OnActivate(); - } - protected override void OnDeactivate() { Pause(); @@ -164,12 +157,11 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties EffectsViewModel.PopulateDescriptors(); } - private void ProfileEditorServiceOnProfileElementSelected(object sender, ProfileElementEventArgs e) + private void ProfileEditorServiceOnProfileElementSelected(object sender, RenderProfileElementEventArgs e) { - PopulateProperties(e.ProfileElement as PropertiesProfileElement); + PopulateProperties(e.RenderProfileElement); } - private void ProfileEditorServiceOnCurrentTimeChanged(object sender, EventArgs e) { NotifyOfPropertyChange(nameof(FormattedCurrentTime)); @@ -190,23 +182,27 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties return groups; } - private void PopulateProperties(PropertiesProfileElement profileElement) + private void PopulateProperties(RenderProfileElement profileElement) { - if (SelectedPropertiesElement != null && SelectedPropertiesElement is EffectProfileElement effectElement) - effectElement.LayerEffectsUpdated -= SelectedElementOnLayerEffectsUpdated; + // Unsubscribe from old selected element + if (SelectedProfileElement != null) + SelectedProfileElement.LayerEffectsUpdated -= SelectedElementOnLayerEffectsUpdated; if (SelectedLayer != null) SelectedLayer.LayerBrushUpdated -= SelectedLayerOnLayerBrushUpdated; + // Clear old properties foreach (var layerPropertyGroupViewModel in LayerPropertyGroups) layerPropertyGroupViewModel.Dispose(); LayerPropertyGroups.Clear(); _brushPropertyGroup = null; - SelectedPropertiesElement = profileElement; - if (SelectedPropertiesElement is EffectProfileElement newEffectElement) - newEffectElement.LayerEffectsUpdated += SelectedElementOnLayerEffectsUpdated; + if (profileElement == null) + return; + + // Subscribe to new element + SelectedProfileElement = profileElement; + SelectedProfileElement.LayerEffectsUpdated += SelectedElementOnLayerEffectsUpdated; - // Apply layer properties if (SelectedLayer != null) { SelectedLayer.LayerBrushUpdated += SelectedLayerOnLayerBrushUpdated; @@ -278,21 +274,21 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties private void ApplyEffects() { - EffectProfileElement effectElement; + RenderProfileElement renderElement; if (SelectedLayer != null) - effectElement = SelectedLayer; + renderElement = SelectedLayer; else if (SelectedFolder != null) - effectElement = SelectedFolder; + renderElement = SelectedFolder; else return; // Remove VMs of effects no longer applied on the layer - var toRemove = LayerPropertyGroups.Where(l => l.LayerPropertyGroup.LayerEffect != null && !effectElement.LayerEffects.Contains(l.LayerPropertyGroup.LayerEffect)).ToList(); + var toRemove = LayerPropertyGroups.Where(l => l.LayerPropertyGroup.LayerEffect != null && !renderElement.LayerEffects.Contains(l.LayerPropertyGroup.LayerEffect)).ToList(); LayerPropertyGroups.RemoveRange(toRemove); foreach (var layerPropertyGroupViewModel in toRemove) layerPropertyGroupViewModel.Dispose(); - foreach (var layerEffect in effectElement.LayerEffects) + foreach (var layerEffect in renderElement.LayerEffects) { if (LayerPropertyGroups.Any(l => l.LayerPropertyGroup.LayerEffect == layerEffect)) continue; diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileEditorViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileEditorViewModel.cs index 383a4bccb..12e16558b 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileEditorViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileEditorViewModel.cs @@ -28,6 +28,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor private PluginSetting _displayConditionsHeight; private PluginSetting _bottomPanelsHeight; private PluginSetting _elementPropertiesWidth; + private ProfileViewModel _profileViewModel; + private ProfileTreeViewModel _profileTreeViewModel; + private LayerPropertiesViewModel _layerPropertiesViewModel; + private DisplayConditionsViewModel _displayConditionsViewModel; public ProfileEditorViewModel(ProfileModule module, ICollection viewModels, @@ -44,21 +48,44 @@ namespace Artemis.UI.Screens.Module.ProfileEditor Module = module; DialogService = dialogService; - DisplayConditionsViewModel = (DisplayConditionsViewModel) viewModels.First(vm => vm is DisplayConditionsViewModel); - LayerPropertiesViewModel = (LayerPropertiesViewModel) viewModels.First(vm => vm is LayerPropertiesViewModel); - ProfileTreeViewModel = (ProfileTreeViewModel) viewModels.First(vm => vm is ProfileTreeViewModel); - ProfileViewModel = (ProfileViewModel) viewModels.First(vm => vm is ProfileViewModel); Profiles = new BindableCollection(); + // Run this first to let VMs activate without causing constant UI updates Items.AddRange(viewModels); + + // Populate the panels + ProfileViewModel = (ProfileViewModel) viewModels.First(vm => vm is ProfileViewModel); + ProfileTreeViewModel = (ProfileTreeViewModel) viewModels.First(vm => vm is ProfileTreeViewModel); + DisplayConditionsViewModel = (DisplayConditionsViewModel) viewModels.First(vm => vm is DisplayConditionsViewModel); + LayerPropertiesViewModel = (LayerPropertiesViewModel) viewModels.First(vm => vm is LayerPropertiesViewModel); } public ProfileModule Module { get; } public IDialogService DialogService { get; } - public DisplayConditionsViewModel DisplayConditionsViewModel { get; } - public LayerPropertiesViewModel LayerPropertiesViewModel { get; } - public ProfileTreeViewModel ProfileTreeViewModel { get; } - public ProfileViewModel ProfileViewModel { get; } + + public DisplayConditionsViewModel DisplayConditionsViewModel + { + get => _displayConditionsViewModel; + set => SetAndNotify(ref _displayConditionsViewModel, value); + } + + public LayerPropertiesViewModel LayerPropertiesViewModel + { + get => _layerPropertiesViewModel; + set => SetAndNotify(ref _layerPropertiesViewModel, value); + } + + public ProfileTreeViewModel ProfileTreeViewModel + { + get => _profileTreeViewModel; + set => SetAndNotify(ref _profileTreeViewModel, value); + } + + public ProfileViewModel ProfileViewModel + { + get => _profileViewModel; + set => SetAndNotify(ref _profileViewModel, value); + } public BindableCollection Profiles { diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/ProfileTreeViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/ProfileTreeViewModel.cs index 032c410fd..247afd9df 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/ProfileTreeViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/ProfileTreeViewModel.cs @@ -1,11 +1,13 @@ using System; using System.Linq; +using System.Threading.Tasks; using System.Windows; using Artemis.Core.Models.Profile; using Artemis.UI.Ninject.Factories; using Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem; using Artemis.UI.Shared.Services.Interfaces; using GongSolutions.Wpf.DragDrop; +using Stylet; namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree { @@ -21,10 +23,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree { _profileEditorService = profileEditorService; _folderVmFactory = folderVmFactory; - - CreateRootFolderViewModel(); - _profileEditorService.ProfileSelected += OnProfileSelected; - _profileEditorService.ProfileElementSelected += OnProfileElementSelected; } public FolderViewModel RootFolder @@ -39,8 +37,12 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree set { if (_updatingTree) return; - SetAndNotify(ref _selectedTreeItem, value); - _profileEditorService.ChangeSelectedProfileElement(value?.ProfileElement); + if (!SetAndNotify(ref _selectedTreeItem, value)) return; + + if (value != null && value.ProfileElement is RenderProfileElement renderElement) + _profileEditorService.ChangeSelectedProfileElement(renderElement); + else + _profileEditorService.ChangeSelectedProfileElement(null); } } @@ -109,6 +111,13 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree RootFolder = _folderVmFactory.Create(folder); _updatingTree = false; + + // Auto-select the first layer + if (_profileEditorService.SelectedProfile != null && SelectedTreeItem == null) + { + if (_profileEditorService.SelectedProfile.GetRootFolder().Children.FirstOrDefault() is RenderProfileElement firstElement) + Execute.PostToUIThread(() => _profileEditorService.ChangeSelectedProfileElement(firstElement)); + } } private static DragDropType GetDragDropType(IDropInfo dropInfo) @@ -140,8 +149,18 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree } } + protected override void OnInitialActivate() + { + _profileEditorService.ProfileSelected += OnProfileSelected; + _profileEditorService.ProfileElementSelected += OnProfileElementSelected; + CreateRootFolderViewModel(); + } + protected override void OnClose() { + _profileEditorService.ProfileSelected -= OnProfileSelected; + _profileEditorService.ProfileElementSelected -= OnProfileElementSelected; + RootFolder?.Dispose(); RootFolder = null; base.OnClose();