diff --git a/src/Artemis.Core/Models/Profile/EffectProfileElement.cs b/src/Artemis.Core/Models/Profile/EffectProfileElement.cs index 3b1aaaab7..a157ab952 100644 --- a/src/Artemis.Core/Models/Profile/EffectProfileElement.cs +++ b/src/Artemis.Core/Models/Profile/EffectProfileElement.cs @@ -62,7 +62,7 @@ namespace Artemis.Core.Models.Profile if (Parent is EffectProfileElement effectParent) shapeClip = shapeClip.Op(effectParent.CreateShapeClip(), SKPathOp.Union); - foreach (var baseLayerEffect in LayerEffects) + foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled)) { var effectClip = baseLayerEffect.InternalCreateShapeClip(Path); shapeClip = shapeClip.Op(effectClip, SKPathOp.Difference); @@ -82,6 +82,7 @@ namespace Artemis.Core.Models.Profile PluginGuid = layerEffect.PluginInfo.Guid, EffectType = layerEffect.GetType().Name, Name = layerEffect.Name, + Enabled = layerEffect.Enabled, HasBeenRenamed = layerEffect.HasBeenRenamed, Order = layerEffect.Order }; diff --git a/src/Artemis.Core/Models/Profile/Folder.cs b/src/Artemis.Core/Models/Profile/Folder.cs index 744a03600..e87fc0378 100644 --- a/src/Artemis.Core/Models/Profile/Folder.cs +++ b/src/Artemis.Core/Models/Profile/Folder.cs @@ -17,6 +17,7 @@ namespace Artemis.Core.Models.Profile Profile = profile; Parent = parent; Name = name; + Enabled = true; _layerEffects = new List(); _expandedPropertyGroups = new List(); @@ -31,6 +32,7 @@ namespace Artemis.Core.Models.Profile Profile = profile; Parent = parent; Name = folderEntity.Name; + Enabled = folderEntity.Enabled; Order = folderEntity.Order; _layerEffects = new List(); @@ -58,7 +60,10 @@ namespace Artemis.Core.Models.Profile public override void Update(double deltaTime) { - foreach (var baseLayerEffect in LayerEffects) + if (!Enabled) + return; + + foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled)) baseLayerEffect.Update(deltaTime); // Iterate the children in reverse because that's how they must be rendered too @@ -71,6 +76,12 @@ namespace Artemis.Core.Models.Profile public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo, SKPaint paint) { + if (!Enabled) + return; + + if (Path == null) + return; + canvas.Save(); canvas.ClipPath(Path); @@ -79,7 +90,7 @@ namespace Artemis.Core.Models.Profile // Pre-processing only affects other pre-processors and the brushes canvas.Save(); - foreach (var baseLayerEffect in LayerEffects) + foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled)) baseLayerEffect.InternalPreProcess(canvas, canvasInfo, new SKPath(Path), groupPaint); // Iterate the children in reverse because the first layer must be rendered last to end up on top @@ -91,12 +102,17 @@ namespace Artemis.Core.Models.Profile // Restore the canvas as to not be affected by pre-processors canvas.Restore(); - foreach (var baseLayerEffect in LayerEffects) + foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled)) baseLayerEffect.InternalPostProcess(canvas, canvasInfo, new SKPath(Path), groupPaint); canvas.Restore(); } + /// + /// Adds a new folder to the bottom of this folder + /// + /// + /// public Folder AddFolder(string name) { var folder = new Folder(Profile, this, name) {Order = Children.LastOrDefault()?.Order ?? 1}; @@ -104,6 +120,20 @@ namespace Artemis.Core.Models.Profile return folder; } + /// + public override void AddChild(ProfileElement child, int? order = null) + { + base.AddChild(child, order); + CalculateRenderProperties(); + } + + /// + public override void RemoveChild(ProfileElement child) + { + base.RemoveChild(child); + CalculateRenderProperties(); + } + public override string ToString() { return $"[Folder] {nameof(Name)}: {Name}, {nameof(Order)}: {Order}"; @@ -134,6 +164,7 @@ namespace Artemis.Core.Models.Profile FolderEntity.Order = Order; FolderEntity.Name = Name; + FolderEntity.Enabled = Enabled; FolderEntity.ProfileId = Profile.EntityId; @@ -152,5 +183,12 @@ namespace Artemis.Core.Models.Profile } #endregion + + internal void Deactivate() + { + var layerEffects = new List(LayerEffects); + foreach (var baseLayerEffect in layerEffects) + DeactivateLayerEffect(baseLayerEffect); + } } } \ No newline at end of file diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs index a15106546..55273c538 100644 --- a/src/Artemis.Core/Models/Profile/Layer.cs +++ b/src/Artemis.Core/Models/Profile/Layer.cs @@ -34,6 +34,7 @@ namespace Artemis.Core.Models.Profile Profile = profile; Parent = parent; Name = name; + Enabled = true; General = new LayerGeneralProperties {IsCorePropertyGroup = true}; Transform = new LayerTransformProperties {IsCorePropertyGroup = true}; @@ -52,6 +53,7 @@ namespace Artemis.Core.Models.Profile Profile = profile; Parent = parent; Name = layerEntity.Name; + Enabled = layerEntity.Enabled; Order = layerEntity.Order; General = new LayerGeneralProperties {IsCorePropertyGroup = true}; Transform = new LayerTransformProperties {IsCorePropertyGroup = true}; @@ -111,6 +113,7 @@ namespace Artemis.Core.Models.Profile LayerEntity.Id = EntityId; LayerEntity.ParentId = Parent?.EntityId ?? new Guid(); LayerEntity.Order = Order; + LayerEntity.Enabled = Enabled; LayerEntity.Name = Name; LayerEntity.ProfileId = Profile.EntityId; LayerEntity.ExpandedPropertyGroups.Clear(); @@ -177,6 +180,9 @@ namespace Artemis.Core.Models.Profile /// public override void Update(double deltaTime) { + if (!Enabled) + return; + if (LayerBrush?.BaseProperties == null || !LayerBrush.BaseProperties.PropertiesInitialized) return; @@ -192,7 +198,7 @@ namespace Artemis.Core.Models.Profile General.Override(TimeSpan.Zero); Transform.Override(TimeSpan.Zero); LayerBrush.BaseProperties.Override(TimeSpan.Zero); - foreach (var baseLayerEffect in LayerEffects) + foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled)) baseLayerEffect.BaseProperties?.Override(TimeSpan.Zero); } else @@ -200,12 +206,12 @@ namespace Artemis.Core.Models.Profile General.Update(deltaTime); Transform.Update(deltaTime); LayerBrush.BaseProperties.Update(deltaTime); - foreach (var baseLayerEffect in LayerEffects) + foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled)) baseLayerEffect.BaseProperties?.Update(deltaTime); } LayerBrush.Update(deltaTime); - foreach (var baseLayerEffect in LayerEffects) + foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled)) baseLayerEffect.Update(deltaTime); } @@ -221,6 +227,9 @@ namespace Artemis.Core.Models.Profile /// public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo, SKPaint paint) { + if (!Enabled) + return; + // Ensure the layer is ready if (Path == null || LayerShape?.Path == null || !General.PropertiesInitialized || !Transform.PropertiesInitialized) return; @@ -230,13 +239,13 @@ namespace Artemis.Core.Models.Profile canvas.Save(); canvas.ClipPath(Path); - + paint.BlendMode = General.BlendMode.CurrentValue; paint.Color = new SKColor(0, 0, 0, (byte) (Transform.Opacity.CurrentValue * 2.55f)); // Pre-processing only affects other pre-processors and the brushes canvas.Save(); - foreach (var baseLayerEffect in LayerEffects) + foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled)) baseLayerEffect.InternalPreProcess(canvas, canvasInfo, new SKPath(Path), paint); // Shape clip must be determined before commiting to any rendering @@ -253,9 +262,9 @@ namespace Artemis.Core.Models.Profile // Restore the canvas as to not be affected by pre-processors canvas.Restore(); - foreach (var baseLayerEffect in LayerEffects) + foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled)) baseLayerEffect.InternalPostProcess(canvas, canvasInfo, new SKPath(Path), paint); - + canvas.Restore(); } diff --git a/src/Artemis.Core/Models/Profile/Profile.cs b/src/Artemis.Core/Models/Profile/Profile.cs index c1c945548..082666b41 100644 --- a/src/Artemis.Core/Models/Profile/Profile.cs +++ b/src/Artemis.Core/Models/Profile/Profile.cs @@ -21,7 +21,7 @@ namespace Artemis.Core.Models.Profile UndoStack = new Stack(); RedoStack = new Stack(); - AddChild(new Folder(this, null, "Root folder")); + AddChild(new Folder(this, this, "Root folder")); ApplyToEntity(); } @@ -80,13 +80,18 @@ namespace Artemis.Core.Models.Profile lock (_children) { + foreach (var folder in GetAllFolders()) + folder.Deactivate(); + foreach (var layer in GetAllLayers()) + layer.Deactivate(); + _children.Clear(); // Populate the profile starting at the root, the rest is populated recursively - var rootFolder = ProfileEntity.Folders.FirstOrDefault(f => f.ParentId == new Guid()); + var rootFolder = ProfileEntity.Folders.FirstOrDefault(f => f.ParentId == EntityId); if (rootFolder == null) - AddChild(new Folder(this, null, "Root folder")); + AddChild(new Folder(this, this, "Root folder")); else - AddChild(new Folder(this, null, rootFolder)); + AddChild(new Folder(this, this, rootFolder)); } } @@ -132,6 +137,8 @@ namespace Artemis.Core.Models.Profile if (!IsActivated) return; + foreach (var folder in GetAllFolders()) + folder.Deactivate(); foreach (var layer in GetAllLayers()) layer.Deactivate(); diff --git a/src/Artemis.Core/Models/Profile/ProfileElement.cs b/src/Artemis.Core/Models/Profile/ProfileElement.cs index c57f4e774..4a050ce99 100644 --- a/src/Artemis.Core/Models/Profile/ProfileElement.cs +++ b/src/Artemis.Core/Models/Profile/ProfileElement.cs @@ -35,6 +35,11 @@ namespace Artemis.Core.Models.Profile /// public string Name { get; set; } + /// + /// Gets or sets the enabled state, if not enabled the element is skipped in render and update + /// + public bool Enabled { get; set; } + /// /// Updates the element /// @@ -79,7 +84,7 @@ namespace Artemis.Core.Models.Profile /// /// The profile element to add /// The order where to place the child (1-based), defaults to the end of the collection - public void AddChild(ProfileElement child, int? order = null) + public virtual void AddChild(ProfileElement child, int? order = null) { lock (_children) { @@ -88,23 +93,25 @@ namespace Artemis.Core.Models.Profile { _children.Add(child); child.Order = _children.Count; - return; + } + // Shift everything after the given order + else + { + foreach (var profileElement in _children.Where(c => c.Order >= order).ToList()) + profileElement.Order++; + + int targetIndex; + if (order == 0) + targetIndex = 0; + else if (order > _children.Count) + targetIndex = _children.Count; + else + targetIndex = _children.FindIndex(c => c.Order == order + 1); + + _children.Insert(targetIndex, child); + child.Order = order.Value; } - // Shift everything after the given order - foreach (var profileElement in _children.Where(c => c.Order >= order).ToList()) - profileElement.Order++; - - int targetIndex; - if (order == 0) - targetIndex = 0; - else if (order > _children.Count) - targetIndex = _children.Count; - else - targetIndex = _children.FindIndex(c => c.Order == order + 1); - - _children.Insert(targetIndex, child); - child.Order = order.Value; child.Parent = this; } } @@ -113,7 +120,7 @@ namespace Artemis.Core.Models.Profile /// Removes a profile element from the collection /// /// The profile element to remove - public void RemoveChild(ProfileElement child) + public virtual void RemoveChild(ProfileElement child) { lock (_children) { diff --git a/src/Artemis.Core/Plugins/LayerEffect/Abstract/BaseLayerEffect.cs b/src/Artemis.Core/Plugins/LayerEffect/Abstract/BaseLayerEffect.cs index ba19e0347..45fb497d8 100644 --- a/src/Artemis.Core/Plugins/LayerEffect/Abstract/BaseLayerEffect.cs +++ b/src/Artemis.Core/Plugins/LayerEffect/Abstract/BaseLayerEffect.cs @@ -27,6 +27,11 @@ namespace Artemis.Core.Plugins.LayerEffect.Abstract /// public string Name { get; set; } + /// + /// Gets or sets the enabled state, if not enabled the effect is skipped in render and update + /// + public bool Enabled { get; set; } + /// /// Gets or sets whether the effect has been renamed by the user, if true consider refraining from changing the name /// programatically diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs index a14067b41..2d3855246 100644 --- a/src/Artemis.Core/Services/CoreService.cs +++ b/src/Artemis.Core/Services/CoreService.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using Artemis.Core.Events; using Artemis.Core.Exceptions; using Artemis.Core.JsonConverters; @@ -23,11 +24,12 @@ namespace Artemis.Core.Services public class CoreService : ICoreService { private readonly ILogger _logger; + private readonly PluginSetting _loggingLevel; private readonly IPluginService _pluginService; private readonly IProfileService _profileService; private readonly IRgbService _rgbService; private readonly ISurfaceService _surfaceService; - private readonly PluginSetting _loggingLevel; + private readonly Stopwatch _frameStopWatch; private List _modules; // ReSharper disable once UnusedParameter.Local - Storage migration service is injected early to ensure it runs before anything else @@ -48,10 +50,13 @@ namespace Artemis.Core.Services _modules = _pluginService.GetPluginsOfType(); _pluginService.PluginEnabled += (sender, args) => _modules = _pluginService.GetPluginsOfType(); _pluginService.PluginDisabled += (sender, args) => _modules = _pluginService.GetPluginsOfType(); - + + _frameStopWatch = new Stopwatch(); + ConfigureJsonConvert(); } + public TimeSpan FrameTime { get; private set; } public bool ModuleUpdatingDisabled { get; set; } public bool ModuleRenderingDisabled { get; set; } @@ -117,6 +122,7 @@ namespace Artemis.Core.Services try { + _frameStopWatch.Restart(); if (!ModuleUpdatingDisabled && _modules != null) { lock (_modules) @@ -157,6 +163,11 @@ namespace Artemis.Core.Services { throw new ArtemisCoreException("Exception during update", e); } + finally + { + _frameStopWatch.Stop(); + FrameTime = _frameStopWatch.Elapsed; + } } private void SurfaceOnUpdated(UpdatedEventArgs args) diff --git a/src/Artemis.Core/Services/Interfaces/ICoreService.cs b/src/Artemis.Core/Services/Interfaces/ICoreService.cs index 2627ebd96..838cca93b 100644 --- a/src/Artemis.Core/Services/Interfaces/ICoreService.cs +++ b/src/Artemis.Core/Services/Interfaces/ICoreService.cs @@ -10,6 +10,11 @@ namespace Artemis.Core.Services.Interfaces /// bool IsInitialized { get; } + /// + /// The time the last frame took to render + /// + TimeSpan FrameTime { get; } + /// /// Gets or sets whether modules are updated each frame by calling their Update method /// diff --git a/src/Artemis.Core/Services/LayerService.cs b/src/Artemis.Core/Services/LayerService.cs index 1323cc32f..2606d5372 100644 --- a/src/Artemis.Core/Services/LayerService.cs +++ b/src/Artemis.Core/Services/LayerService.cs @@ -86,6 +86,7 @@ namespace Artemis.Core.Services effect.ProfileElement = effectElement; effect.EntityId = Guid.NewGuid(); + effect.Enabled = true; effect.Order = effectElement.LayerEffects.Count + 1; effect.Descriptor = layerEffectDescriptor; @@ -109,15 +110,8 @@ namespace Artemis.Core.Services var layerEffectProviders = _pluginService.GetPluginsOfType(); var descriptors = layerEffectProviders.SelectMany(l => l.LayerEffectDescriptors).ToList(); - - List entities; - if (effectElement is Layer layer) - entities = layer.LayerEntity.LayerEffects.OrderByDescending(e => e.Order).ToList(); - else if (effectElement is Folder folder) - entities = folder.FolderEntity.LayerEffects.OrderByDescending(e => e.Order).ToList(); - else - throw new ArtemisCoreException("Provided effect element is of an unsupported type, must be Layer of Folder"); - + var entities = effectElement.EffectsEntity.LayerEffects.OrderByDescending(e => e.Order).ToList(); + foreach (var layerEffectEntity in entities) { // Get a matching descriptor @@ -133,6 +127,7 @@ namespace Artemis.Core.Services effect.EntityId = layerEffectEntity.Id; effect.Order = layerEffectEntity.Order; effect.Name = layerEffectEntity.Name; + effect.Enabled = layerEffectEntity.Enabled; effect.Descriptor = descriptor; effect.Initialize(this); diff --git a/src/Artemis.Storage/Entities/Profile/FolderEntity.cs b/src/Artemis.Storage/Entities/Profile/FolderEntity.cs index 06731f2a5..a48924b3c 100644 --- a/src/Artemis.Storage/Entities/Profile/FolderEntity.cs +++ b/src/Artemis.Storage/Entities/Profile/FolderEntity.cs @@ -19,6 +19,7 @@ namespace Artemis.Storage.Entities.Profile public int Order { get; set; } public string Name { get; set; } + public bool Enabled { get; set; } [BsonRef("ProfileEntity")] public ProfileEntity Profile { get; set; } diff --git a/src/Artemis.Storage/Entities/Profile/LayerEffectEntity.cs b/src/Artemis.Storage/Entities/Profile/LayerEffectEntity.cs index 85d3d1a34..d6dce29be 100644 --- a/src/Artemis.Storage/Entities/Profile/LayerEffectEntity.cs +++ b/src/Artemis.Storage/Entities/Profile/LayerEffectEntity.cs @@ -8,6 +8,7 @@ namespace Artemis.Storage.Entities.Profile public Guid PluginGuid { get; set; } public string EffectType { get; set; } public string Name { get; set; } + public bool Enabled { get; set; } public bool HasBeenRenamed { get; set; } public int Order { get; set; } } diff --git a/src/Artemis.Storage/Entities/Profile/LayerEntity.cs b/src/Artemis.Storage/Entities/Profile/LayerEntity.cs index 30317cb22..65b2c3919 100644 --- a/src/Artemis.Storage/Entities/Profile/LayerEntity.cs +++ b/src/Artemis.Storage/Entities/Profile/LayerEntity.cs @@ -20,6 +20,7 @@ namespace Artemis.Storage.Entities.Profile public int Order { get; set; } public string Name { get; set; } + public bool Enabled { get; set; } public List Leds { get; set; } diff --git a/src/Artemis.Storage/Migrations/ProfileEntitiesEnabledMigration.cs b/src/Artemis.Storage/Migrations/ProfileEntitiesEnabledMigration.cs new file mode 100644 index 000000000..50dd42251 --- /dev/null +++ b/src/Artemis.Storage/Migrations/ProfileEntitiesEnabledMigration.cs @@ -0,0 +1,34 @@ +using Artemis.Storage.Entities.Profile; +using Artemis.Storage.Migrations.Interfaces; +using LiteDB; + +namespace Artemis.Storage.Migrations +{ + public class ProfileEntitiesEnabledMigration : IStorageMigration + { + public int UserVersion => 2; + + public void Apply(LiteRepository repository) + { + var profiles = repository.Query().ToList(); + foreach (var profileEntity in profiles) + { + foreach (var profileEntityFolder in profileEntity.Folders) + { + profileEntityFolder.Enabled = true; + foreach (var layerEffectEntity in profileEntityFolder.LayerEffects) + layerEffectEntity.Enabled = true; + } + + foreach (var profileEntityLayer in profileEntity.Layers) + { + profileEntityLayer.Enabled = true; + foreach (var layerEffectEntity in profileEntityLayer.LayerEffects) + layerEffectEntity.Enabled = true; + } + + repository.Upsert(profileEntity); + } + } + } +} \ 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 064b4c2a5..2623b8c32 100644 --- a/src/Artemis.UI.Shared/Services/Interfaces/IProfileEditorService.cs +++ b/src/Artemis.UI.Shared/Services/Interfaces/IProfileEditorService.cs @@ -19,7 +19,7 @@ namespace Artemis.UI.Shared.Services.Interfaces IKernel Kernel { get; } void ChangeSelectedProfile(Profile profile); - void UpdateSelectedProfile(bool includeChildren); + void UpdateSelectedProfile(); void ChangeSelectedProfileElement(ProfileElement profileElement); void UpdateSelectedProfileElement(); void UpdateProfilePreview(); diff --git a/src/Artemis.UI.Shared/Services/ProfileEditorService.cs b/src/Artemis.UI.Shared/Services/ProfileEditorService.cs index 88231e319..f48a10218 100644 --- a/src/Artemis.UI.Shared/Services/ProfileEditorService.cs +++ b/src/Artemis.UI.Shared/Services/ProfileEditorService.cs @@ -71,9 +71,9 @@ namespace Artemis.UI.Shared.Services OnSelectedProfileChanged(profileElementEvent); } - public void UpdateSelectedProfile(bool includeChildren) + public void UpdateSelectedProfile() { - _profileService.UpdateProfile(SelectedProfile, includeChildren); + _profileService.UpdateProfile(SelectedProfile, true); UpdateProfilePreview(); OnSelectedProfileElementUpdated(new ProfileElementEventArgs(SelectedProfile)); } diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj index e461d9c69..e76803bc8 100644 --- a/src/Artemis.UI/Artemis.UI.csproj +++ b/src/Artemis.UI/Artemis.UI.csproj @@ -9,7 +9,6 @@ en-US Adds third-party support for RGB keyboards to games. Copyright © Robert Beekman - 2020 - 1.0.0.0 2.0.0.0 true MinimumRecommendedRules.ruleset @@ -27,6 +26,18 @@ + 2.0.0.0 + 2.0.0 + + + 2.0-{chash:6} + true + true + true + v[0-9]* + true + git + true @@ -141,6 +152,10 @@ + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + 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 75167a483..3125d238b 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerEffects/EffectsViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerEffects/EffectsViewModel.cs @@ -5,6 +5,7 @@ using Artemis.Core.Models.Profile; using Artemis.Core.Plugins.Abstract; using Artemis.Core.Plugins.LayerEffect; using Artemis.Core.Services.Interfaces; +using Artemis.UI.Shared.Services.Interfaces; using Stylet; namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.LayerEffects @@ -12,12 +13,14 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.LayerEffects public class EffectsViewModel : PropertyChangedBase { private readonly ILayerService _layerService; + private readonly IProfileEditorService _profileEditorService; private readonly IPluginService _pluginService; - public EffectsViewModel(LayerPropertiesViewModel layerPropertiesViewModel, IPluginService pluginService, ILayerService layerService) + public EffectsViewModel(LayerPropertiesViewModel layerPropertiesViewModel, IPluginService pluginService, ILayerService layerService, IProfileEditorService profileEditorService) { _pluginService = pluginService; _layerService = layerService; + _profileEditorService = profileEditorService; LayerPropertiesViewModel = layerPropertiesViewModel; LayerEffectDescriptors = new BindableCollection(); PropertyChanged += HandleSelectedLayerEffectChanged; @@ -58,6 +61,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.LayerEffects { await Task.Delay(500); _layerService.AddLayerEffect(effectElement, 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 d35ef1d81..d0ccdaa58 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/LayerPropertiesViewModel.cs @@ -310,7 +310,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties MoveAfter(source, target); ApplyCurrentEffectsOrder(); - ProfileEditorService.UpdateSelectedProfile(true); + ProfileEditorService.UpdateSelectedProfile(); } private void MoveBefore(LayerPropertyGroupViewModel source, LayerPropertyGroupViewModel target) diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupView.xaml index 9db002c81..6deeeaa8f 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupView.xaml +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupView.xaml @@ -93,7 +93,6 @@ - - + Kind="{Binding LayerPropertyGroupViewModel.LayerPropertyGroup.LayerEffect.Descriptor.Icon}" + Margin="0 5 5 0" + Background="Transparent" /> Effect @@ -132,25 +131,36 @@ Margin="0 5" Visibility="{Binding LayerPropertyGroupViewModel.LayerPropertyGroup.LayerEffect.Name, Converter={StaticResource NullToVisibilityConverter}}" /> - + + + + + + + - diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupViewModel.cs index 5af7dbfb2..e47b45076 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/LayerProperties/Tree/TreePropertyGroupViewModel.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.Diagnostics; using Artemis.Core.Services.Interfaces; using Artemis.UI.Screens.Module.ProfileEditor.Dialogs; using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Abstract; @@ -37,14 +38,19 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Tree { LayerPropertyGroupViewModel.LayerPropertyGroup.LayerEffect.Name = newName; LayerPropertyGroupViewModel.LayerPropertyGroup.LayerEffect.HasBeenRenamed = true; - _profileEditorService.UpdateSelectedProfile(true); + _profileEditorService.UpdateSelectedProfile(); } } public void DeleteEffect() { _layerService.RemoveLayerEffect(LayerPropertyGroupViewModel.LayerPropertyGroup.LayerEffect); - _profileEditorService.UpdateSelectedProfile(true); + _profileEditorService.UpdateSelectedProfile(); + } + + public void EnableToggled() + { + _profileEditorService.UpdateSelectedProfile(); } } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/ProfileTreeViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/ProfileTreeViewModel.cs index 925e23b76..272530ad6 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/ProfileTreeViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/ProfileTreeViewModel.cs @@ -77,7 +77,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree break; } - _profileEditorService.UpdateSelectedProfile(true); + _profileEditorService.UpdateSelectedProfile(); } // ReSharper disable once UnusedMember.Global - Called from view diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/FolderView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/FolderView.xaml index 2180909ce..f094176b4 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/FolderView.xaml +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/FolderView.xaml @@ -36,13 +36,28 @@ - - + + + + + + - - - - + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/LayerView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/LayerView.xaml index e955fda0d..b0ade2a89 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/LayerView.xaml +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/LayerView.xaml @@ -25,15 +25,32 @@ - - - + + + + + + + + - - + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/TreeItemViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/TreeItemViewModel.cs index e318e19b4..863a7e2da 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/TreeItemViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/ProfileTree/TreeItem/TreeItemViewModel.cs @@ -1,4 +1,5 @@ using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Threading.Tasks; using Artemis.Core.Models.Profile; @@ -37,9 +38,16 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem ProfileElement = profileElement; Children = new BindableCollection(); + ProfileElement.PropertyChanged += HandleProfileElementEnabledChanged; UpdateProfileElements(); } + private void HandleProfileElementEnabledChanged(object sender, PropertyChangedEventArgs e) + { + if (e.PropertyName == nameof(ProfileElement.Enabled)) + _profileEditorService.UpdateSelectedProfile(); + } + public TreeItemViewModel Parent { get; set; } public ProfileElement ProfileElement { get; set; } @@ -113,7 +121,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem ProfileElement.AddChild(new Folder(ProfileElement.Profile, ProfileElement, "New folder")); UpdateProfileElements(); - _profileEditorService.UpdateSelectedProfile(true); + _profileEditorService.UpdateSelectedProfile(); } public void AddLayer() @@ -123,7 +131,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem _layerService.CreateLayer(ProfileElement.Profile, ProfileElement, "New layer"); UpdateProfileElements(); - _profileEditorService.UpdateSelectedProfile(true); + _profileEditorService.UpdateSelectedProfile(); } // ReSharper disable once UnusedMember.Global - Called from view @@ -139,7 +147,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem if (result is string newName) { ProfileElement.Name = newName; - _profileEditorService.UpdateSelectedProfile(true); + _profileEditorService.UpdateSelectedProfile(); } } @@ -160,7 +168,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree.TreeItem parent.RemoveExistingElement(this); parent.UpdateProfileElements(); - _profileEditorService.UpdateSelectedProfile(true); + _profileEditorService.UpdateSelectedProfile(); } public void UpdateProfileElements() diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/SelectionToolViewModel.cs b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/SelectionToolViewModel.cs index 742cb2fd6..e6750bde0 100644 --- a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/SelectionToolViewModel.cs +++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/Tools/SelectionToolViewModel.cs @@ -56,7 +56,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools newLayer.AddLeds(selectedLeds); ProfileEditorService.ChangeSelectedProfileElement(newLayer); ProfileEditorService.UpdateSelectedProfileElement(); - ProfileEditorService.UpdateSelectedProfile(false); } // If no folder selected, apply it to a new layer in the root folder else @@ -66,7 +65,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools newLayer.AddLeds(selectedLeds); ProfileEditorService.ChangeSelectedProfileElement(newLayer); ProfileEditorService.UpdateSelectedProfileElement(); - ProfileEditorService.UpdateSelectedProfile(false); } } diff --git a/src/Artemis.UI/Screens/RootView.xaml b/src/Artemis.UI/Screens/RootView.xaml index a2c8d0ea3..505f2318e 100644 --- a/src/Artemis.UI/Screens/RootView.xaml +++ b/src/Artemis.UI/Screens/RootView.xaml @@ -11,7 +11,7 @@ mc:Ignorable="d" FadeContentIfInactive="False" Icon="/Resources/Images/Logo/logo-512.png" - Title="Artemis" + Title="{Binding WindowTitle}" TitleBarIcon="{StaticResource BowIcon}" Foreground="{DynamicResource MaterialDesignBody}" Background="{DynamicResource MaterialDesignPaper}" diff --git a/src/Artemis.UI/Screens/RootViewModel.cs b/src/Artemis.UI/Screens/RootViewModel.cs index a25ca502e..62bacff72 100644 --- a/src/Artemis.UI/Screens/RootViewModel.cs +++ b/src/Artemis.UI/Screens/RootViewModel.cs @@ -1,9 +1,12 @@ using System.ComponentModel; +using System.Reflection; using System.Threading.Tasks; +using System.Timers; using System.Windows; using System.Windows.Input; using Artemis.Core.Plugins.Models; using Artemis.Core.Services; +using Artemis.Core.Services.Interfaces; using Artemis.UI.Events; using Artemis.UI.Screens.Settings; using Artemis.UI.Screens.Sidebar; @@ -15,16 +18,21 @@ namespace Artemis.UI.Screens { public class RootViewModel : Conductor { - private readonly IEventAggregator _eventAggregator; private readonly PluginSetting _colorScheme; - private bool _lostFocus; + private readonly ICoreService _coreService; + private readonly IEventAggregator _eventAggregator; private readonly ThemeWatcher _themeWatcher; + private bool _lostFocus; + private readonly Timer _titleUpdateTimer; - public RootViewModel(IEventAggregator eventAggregator, SidebarViewModel sidebarViewModel, ISettingsService settingsService) + public RootViewModel(IEventAggregator eventAggregator, SidebarViewModel sidebarViewModel, ISettingsService settingsService, ICoreService coreService) { SidebarViewModel = sidebarViewModel; _eventAggregator = eventAggregator; + _coreService = coreService; + _titleUpdateTimer = new Timer(500); + _titleUpdateTimer.Elapsed += (sender, args) => UpdateWindowTitle(); _colorScheme = settingsService.GetSetting("UI.ColorScheme", ApplicationColorScheme.Automatic); _colorScheme.SettingChanged += (sender, args) => ApplyColorSchemeSetting(); _themeWatcher = new ThemeWatcher(); @@ -40,6 +48,8 @@ namespace Artemis.UI.Screens public bool IsSidebarVisible { get; set; } public bool ActiveItemReady { get; set; } + public string WindowTitle { get; set; } + public void WindowDeactivated() { var windowState = ((Window) View).WindowState; @@ -69,6 +79,26 @@ namespace Artemis.UI.Screens _eventAggregator.Publish(new MainWindowKeyEvent(false, e)); } + protected override void OnActivate() + { + UpdateWindowTitle(); + _titleUpdateTimer.Start(); + } + + protected override void OnDeactivate() + { + _titleUpdateTimer.Stop(); + } + + private void UpdateWindowTitle() + { + var versionAttribute = typeof(RootViewModel).Assembly.GetCustomAttribute(); + if (versionAttribute != null) + WindowTitle = $"Artemis {versionAttribute.InformationalVersion} - Frame time: {_coreService.FrameTime.TotalMilliseconds:F2} ms"; + else + WindowTitle = $"Artemis - Frame time: {_coreService.FrameTime.TotalMilliseconds:F2} ms"; + } + private void SidebarViewModelOnPropertyChanged(object sender, PropertyChangedEventArgs e) { if (e.PropertyName == nameof(SidebarViewModel.SelectedItem))