mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-11 19:36:28 +00:00
Profiles - Finished dispose implementation
Profiles - Added transition between active profiles Core - Added startup animation
This commit is contained in:
1 parent
c0bdd8cf26
commit
d955bc8635
43 files changed
+1908
-361
No files matched your search
@@ -70,4 +70,9 @@
|
||||
<HintPath>..\..\..\RGB.NET\bin\netstandard2.0\RGB.NET.Groups.dll</HintPath>
|
||||
</Reference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Update="Resources\intro-profile.json">
|
||||
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||
</None>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -2,6 +2,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Core.Plugins.LayerEffect.Abstract;
|
||||
using Artemis.Core.Utilities;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using Artemis.Storage.Entities.Profile.Abstract;
|
||||
using SkiaSharp;
|
||||
@@ -61,9 +62,13 @@ namespace Artemis.Core.Models.Profile
|
||||
|
||||
internal FolderEntity FolderEntity { get; set; }
|
||||
internal override RenderElementEntity RenderElementEntity => FolderEntity;
|
||||
public bool IsRootFolder => Parent == Profile;
|
||||
|
||||
public override void Update(double deltaTime)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Folder");
|
||||
|
||||
if (!Enabled)
|
||||
return;
|
||||
|
||||
@@ -89,6 +94,9 @@ namespace Artemis.Core.Models.Profile
|
||||
|
||||
public override void OverrideProgress(TimeSpan timeOverride, bool stickToMainSegment)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Folder");
|
||||
|
||||
if (!Enabled)
|
||||
return;
|
||||
|
||||
@@ -125,6 +133,9 @@ namespace Artemis.Core.Models.Profile
|
||||
|
||||
public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Folder");
|
||||
|
||||
if (Path == null || !Enabled || !Children.Any(c => c.Enabled))
|
||||
return;
|
||||
|
||||
@@ -172,6 +183,13 @@ namespace Artemis.Core.Models.Profile
|
||||
profileElement.Render(deltaTime, folderCanvas, _folderBitmap.Info);
|
||||
folderCanvas.Restore();
|
||||
}
|
||||
|
||||
// If required, apply the opacity override of the module to the root folder
|
||||
if (IsRootFolder && Profile.Module.OpacityOverride < 1)
|
||||
{
|
||||
var multiplier = Easings.SineEaseInOut(Profile.Module.OpacityOverride);
|
||||
folderPaint.Color = folderPaint.Color.WithAlpha((byte) (folderPaint.Color.Alpha * multiplier));
|
||||
}
|
||||
|
||||
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
||||
baseLayerEffect.PostProcess(canvas, canvasInfo, folderPath, folderPaint);
|
||||
@@ -187,6 +205,9 @@ namespace Artemis.Core.Models.Profile
|
||||
/// <returns></returns>
|
||||
public Folder AddFolder(string name)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Folder");
|
||||
|
||||
var folder = new Folder(Profile, this, name) {Order = Children.LastOrDefault()?.Order ?? 1};
|
||||
AddChild(folder);
|
||||
return folder;
|
||||
@@ -195,6 +216,9 @@ namespace Artemis.Core.Models.Profile
|
||||
/// <inheritdoc />
|
||||
public override void AddChild(ProfileElement child, int? order = null)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Folder");
|
||||
|
||||
base.AddChild(child, order);
|
||||
CalculateRenderProperties();
|
||||
}
|
||||
@@ -202,6 +226,9 @@ namespace Artemis.Core.Models.Profile
|
||||
/// <inheritdoc />
|
||||
public override void RemoveChild(ProfileElement child)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Folder");
|
||||
|
||||
base.RemoveChild(child);
|
||||
CalculateRenderProperties();
|
||||
}
|
||||
@@ -213,6 +240,9 @@ namespace Artemis.Core.Models.Profile
|
||||
|
||||
public void CalculateRenderProperties()
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Folder");
|
||||
|
||||
var path = new SKPath {FillType = SKPathFillType.Winding};
|
||||
foreach (var child in Children)
|
||||
{
|
||||
@@ -234,16 +264,27 @@ namespace Artemis.Core.Models.Profile
|
||||
if (!disposing)
|
||||
return;
|
||||
|
||||
_folderBitmap?.Dispose();
|
||||
foreach (var baseLayerEffect in LayerEffects)
|
||||
baseLayerEffect.Dispose();
|
||||
_layerEffects.Clear();
|
||||
|
||||
foreach (var profileElement in Children)
|
||||
profileElement.Dispose();
|
||||
ChildrenList.Clear();
|
||||
|
||||
_folderBitmap?.Dispose();
|
||||
_folderBitmap = null;
|
||||
|
||||
Profile = null;
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
|
||||
internal override void ApplyToEntity()
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Folder");
|
||||
|
||||
FolderEntity.Id = EntityId;
|
||||
FolderEntity.ParentId = Parent?.EntityId ?? new Guid();
|
||||
|
||||
@@ -262,16 +303,6 @@ namespace Artemis.Core.Models.Profile
|
||||
DisplayConditionGroup?.ApplyToEntity();
|
||||
}
|
||||
|
||||
internal void Deactivate()
|
||||
{
|
||||
_folderBitmap?.Dispose();
|
||||
_folderBitmap = null;
|
||||
|
||||
var layerEffects = new List<BaseLayerEffect>(LayerEffects);
|
||||
foreach (var baseLayerEffect in layerEffects)
|
||||
DeactivateLayerEffect(baseLayerEffect);
|
||||
}
|
||||
|
||||
#region Events
|
||||
|
||||
public event EventHandler RenderPropertiesUpdated;
|
||||
|
||||
@@ -126,6 +126,9 @@ namespace Artemis.Core.Models.Profile
|
||||
/// <inheritdoc />
|
||||
public override List<BaseLayerPropertyKeyframe> GetAllKeyframes()
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Layer");
|
||||
|
||||
var keyframes = base.GetAllKeyframes();
|
||||
|
||||
foreach (var baseLayerProperty in General.GetAllLayerProperties())
|
||||
@@ -143,22 +146,36 @@ namespace Artemis.Core.Models.Profile
|
||||
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (!disposing)
|
||||
if (!disposing)
|
||||
return;
|
||||
|
||||
_general?.Dispose();
|
||||
_layerBitmap?.Dispose();
|
||||
_disposed = true;
|
||||
|
||||
// Brush first in case it depends on any of the other disposables during it's own disposal
|
||||
_layerBrush?.Dispose();
|
||||
_transform?.Dispose();
|
||||
_layerBrush = null;
|
||||
|
||||
foreach (var baseLayerEffect in LayerEffects)
|
||||
baseLayerEffect.Dispose();
|
||||
_layerEffects.Clear();
|
||||
|
||||
_general?.Dispose();
|
||||
_general = null;
|
||||
_layerBitmap?.Dispose();
|
||||
_layerBitmap = null;
|
||||
_transform?.Dispose();
|
||||
_transform = null;
|
||||
|
||||
Profile = null;
|
||||
}
|
||||
|
||||
#region Storage
|
||||
|
||||
internal override void ApplyToEntity()
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Layer");
|
||||
|
||||
// Properties
|
||||
LayerEntity.Id = EntityId;
|
||||
LayerEntity.ParentId = Parent?.EntityId ?? new Guid();
|
||||
@@ -231,6 +248,9 @@ namespace Artemis.Core.Models.Profile
|
||||
/// <inheritdoc />
|
||||
public override void Update(double deltaTime)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Layer");
|
||||
|
||||
if (!Enabled || LayerBrush?.BaseProperties == null || !LayerBrush.BaseProperties.PropertiesInitialized)
|
||||
return;
|
||||
|
||||
@@ -259,6 +279,9 @@ namespace Artemis.Core.Models.Profile
|
||||
|
||||
public override void OverrideProgress(TimeSpan timeOverride, bool stickToMainSegment)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Layer");
|
||||
|
||||
if (!Enabled || LayerBrush?.BaseProperties == null || !LayerBrush.BaseProperties.PropertiesInitialized)
|
||||
return;
|
||||
|
||||
@@ -268,9 +291,7 @@ namespace Artemis.Core.Models.Profile
|
||||
{
|
||||
if (!DisplayContinuously)
|
||||
{
|
||||
var position = timeOverride + StartSegmentLength;
|
||||
if (position > StartSegmentLength + EndSegmentLength)
|
||||
TimelinePosition = StartSegmentLength + EndSegmentLength;
|
||||
TimelinePosition = StartSegmentLength + timeOverride;
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -301,6 +322,9 @@ namespace Artemis.Core.Models.Profile
|
||||
/// <inheritdoc />
|
||||
public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Layer");
|
||||
|
||||
if (!Enabled || TimelinePosition > TimelineLength)
|
||||
return;
|
||||
|
||||
@@ -424,6 +448,9 @@ namespace Artemis.Core.Models.Profile
|
||||
|
||||
internal void CalculateRenderProperties()
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Layer");
|
||||
|
||||
if (!Leds.Any())
|
||||
Path = new SKPath();
|
||||
else
|
||||
@@ -448,6 +475,9 @@ namespace Artemis.Core.Models.Profile
|
||||
|
||||
internal SKPoint GetLayerAnchorPosition(SKPath layerPath, bool zeroBased = false)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Layer");
|
||||
|
||||
var positionProperty = Transform.Position.CurrentValue;
|
||||
|
||||
// Start at the center of the shape
|
||||
@@ -469,6 +499,9 @@ namespace Artemis.Core.Models.Profile
|
||||
/// <param name="path"></param>
|
||||
public void IncludePathInTranslation(SKPath path, bool zeroBased)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Layer");
|
||||
|
||||
var sizeProperty = Transform.Scale.CurrentValue;
|
||||
var rotationProperty = Transform.Rotation.CurrentValue;
|
||||
|
||||
@@ -498,6 +531,9 @@ namespace Artemis.Core.Models.Profile
|
||||
/// </summary>
|
||||
public void ExcludePathFromTranslation(SKPath path, bool zeroBased)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Layer");
|
||||
|
||||
var sizeProperty = Transform.Scale.CurrentValue;
|
||||
var rotationProperty = Transform.Rotation.CurrentValue;
|
||||
|
||||
@@ -531,6 +567,9 @@ namespace Artemis.Core.Models.Profile
|
||||
/// <returns>The number of transformations applied</returns>
|
||||
public int ExcludeCanvasFromTranslation(SKCanvas canvas, bool zeroBased)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Layer");
|
||||
|
||||
var sizeProperty = Transform.Scale.CurrentValue;
|
||||
var rotationProperty = Transform.Rotation.CurrentValue;
|
||||
|
||||
@@ -568,6 +607,9 @@ namespace Artemis.Core.Models.Profile
|
||||
/// <param name="led">The LED to add</param>
|
||||
public void AddLed(ArtemisLed led)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Layer");
|
||||
|
||||
_leds.Add(led);
|
||||
CalculateRenderProperties();
|
||||
}
|
||||
@@ -578,6 +620,9 @@ namespace Artemis.Core.Models.Profile
|
||||
/// <param name="leds">The LEDs to add</param>
|
||||
public void AddLeds(IEnumerable<ArtemisLed> leds)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Layer");
|
||||
|
||||
_leds.AddRange(leds);
|
||||
CalculateRenderProperties();
|
||||
}
|
||||
@@ -588,6 +633,9 @@ namespace Artemis.Core.Models.Profile
|
||||
/// <param name="led">The LED to remove</param>
|
||||
public void RemoveLed(ArtemisLed led)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Layer");
|
||||
|
||||
_leds.Remove(led);
|
||||
CalculateRenderProperties();
|
||||
}
|
||||
@@ -597,12 +645,18 @@ namespace Artemis.Core.Models.Profile
|
||||
/// </summary>
|
||||
public void ClearLeds()
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Layer");
|
||||
|
||||
_leds.Clear();
|
||||
CalculateRenderProperties();
|
||||
}
|
||||
|
||||
internal void PopulateLeds(ArtemisSurface surface)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Layer");
|
||||
|
||||
var leds = new List<ArtemisLed>();
|
||||
|
||||
// Get the surface LEDs for this layer
|
||||
@@ -623,17 +677,6 @@ namespace Artemis.Core.Models.Profile
|
||||
|
||||
#region Activation
|
||||
|
||||
internal void Deactivate()
|
||||
{
|
||||
_layerBitmap?.Dispose();
|
||||
_layerBitmap = null;
|
||||
|
||||
DeactivateLayerBrush();
|
||||
var layerEffects = new List<BaseLayerEffect>(LayerEffects);
|
||||
foreach (var baseLayerEffect in layerEffects)
|
||||
DeactivateLayerEffect(baseLayerEffect);
|
||||
}
|
||||
|
||||
internal void DeactivateLayerBrush()
|
||||
{
|
||||
if (LayerBrush == null)
|
||||
|
||||
@@ -28,5 +28,9 @@ namespace Artemis.Core.Models.Profile
|
||||
protected override void EnableProperties()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void DisableProperties()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -110,6 +110,8 @@ namespace Artemis.Core.Models.Profile
|
||||
public void Dispose()
|
||||
{
|
||||
DisableProperties();
|
||||
foreach (var layerPropertyGroup in _layerPropertyGroups)
|
||||
layerPropertyGroup.Dispose();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -30,5 +30,9 @@ namespace Artemis.Core.Models.Profile
|
||||
protected override void EnableProperties()
|
||||
{
|
||||
}
|
||||
|
||||
protected override void DisableProperties()
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -57,6 +57,8 @@ namespace Artemis.Core.Models.Profile
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Profile");
|
||||
if (!IsActivated)
|
||||
throw new ArtemisCoreException($"Cannot update inactive profile: {this}");
|
||||
|
||||
@@ -69,6 +71,8 @@ namespace Artemis.Core.Models.Profile
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Profile");
|
||||
if (!IsActivated)
|
||||
throw new ArtemisCoreException($"Cannot render inactive profile: {this}");
|
||||
|
||||
@@ -79,21 +83,26 @@ namespace Artemis.Core.Models.Profile
|
||||
|
||||
public Folder GetRootFolder()
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Profile");
|
||||
|
||||
return (Folder) Children.Single();
|
||||
}
|
||||
|
||||
public void ApplyToProfile()
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Profile");
|
||||
|
||||
Name = ProfileEntity.Name;
|
||||
|
||||
lock (ChildrenList)
|
||||
{
|
||||
foreach (var folder in GetAllFolders())
|
||||
folder.Deactivate();
|
||||
foreach (var layer in GetAllLayers())
|
||||
layer.Deactivate();
|
||||
|
||||
// Remove the old profile tree
|
||||
foreach (var profileElement in Children)
|
||||
profileElement.Dispose();
|
||||
ChildrenList.Clear();
|
||||
|
||||
// Populate the profile starting at the root, the rest is populated recursively
|
||||
var rootFolder = ProfileEntity.Folders.FirstOrDefault(f => f.ParentId == EntityId);
|
||||
if (rootFolder == null)
|
||||
@@ -113,13 +122,21 @@ namespace Artemis.Core.Models.Profile
|
||||
if (!disposing)
|
||||
return;
|
||||
|
||||
Deactivate();
|
||||
OnDeactivating();
|
||||
|
||||
foreach (var profileElement in Children)
|
||||
profileElement.Dispose();
|
||||
ChildrenList.Clear();
|
||||
|
||||
IsActivated = false;
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
internal override void ApplyToEntity()
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Profile");
|
||||
|
||||
ProfileEntity.Id = EntityId;
|
||||
ProfileEntity.PluginGuid = Module.PluginInfo.Guid;
|
||||
ProfileEntity.Name = Name;
|
||||
@@ -139,6 +156,8 @@ namespace Artemis.Core.Models.Profile
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Profile");
|
||||
if (IsActivated)
|
||||
return;
|
||||
|
||||
@@ -148,25 +167,11 @@ namespace Artemis.Core.Models.Profile
|
||||
}
|
||||
}
|
||||
|
||||
internal void Deactivate()
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
if (!IsActivated)
|
||||
return;
|
||||
|
||||
foreach (var folder in GetAllFolders())
|
||||
folder.Deactivate();
|
||||
foreach (var layer in GetAllLayers())
|
||||
layer.Deactivate();
|
||||
|
||||
IsActivated = false;
|
||||
OnDeactivated();
|
||||
}
|
||||
}
|
||||
|
||||
internal void PopulateLeds(ArtemisSurface surface)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("Profile");
|
||||
|
||||
foreach (var layer in GetAllLayers())
|
||||
layer.PopulateLeds(surface);
|
||||
}
|
||||
@@ -174,7 +179,7 @@ namespace Artemis.Core.Models.Profile
|
||||
#region Events
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the profile is being activated.
|
||||
/// Occurs when the profile has been activated.
|
||||
/// </summary>
|
||||
public event EventHandler Activated;
|
||||
|
||||
@@ -188,7 +193,7 @@ namespace Artemis.Core.Models.Profile
|
||||
Activated?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void OnDeactivated()
|
||||
private void OnDeactivating()
|
||||
{
|
||||
Deactivated?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
@@ -9,16 +9,16 @@ namespace Artemis.Core.Models.Profile
|
||||
internal ProfileDescriptor(ProfileModule profileModule, ProfileEntity profileEntity)
|
||||
{
|
||||
ProfileModule = profileModule;
|
||||
ProfileEntity = profileEntity;
|
||||
|
||||
Id = profileEntity.Id;
|
||||
Name = profileEntity.Name;
|
||||
IsLastActiveProfile = profileEntity.IsActive;
|
||||
}
|
||||
|
||||
|
||||
public bool IsLastActiveProfile { get; set; }
|
||||
|
||||
public Guid Id { get; }
|
||||
public ProfileModule ProfileModule { get; }
|
||||
public string Name { get; }
|
||||
|
||||
internal ProfileEntity ProfileEntity { get; }
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,7 @@ namespace Artemis.Core.Models.Profile
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
protected bool _disposed;
|
||||
private bool _enabled;
|
||||
private Guid _entityId;
|
||||
private string _name;
|
||||
@@ -98,6 +99,9 @@ namespace Artemis.Core.Models.Profile
|
||||
|
||||
public List<Folder> GetAllFolders()
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException(GetType().Name);
|
||||
|
||||
var folders = new List<Folder>();
|
||||
foreach (var childFolder in Children.Where(c => c is Folder).Cast<Folder>())
|
||||
{
|
||||
@@ -112,6 +116,9 @@ namespace Artemis.Core.Models.Profile
|
||||
|
||||
public List<Layer> GetAllLayers()
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException(GetType().Name);
|
||||
|
||||
var layers = new List<Layer>();
|
||||
|
||||
// Add all layers in this element
|
||||
@@ -131,6 +138,9 @@ namespace Artemis.Core.Models.Profile
|
||||
/// <param name="order">The order where to place the child (1-based), defaults to the end of the collection</param>
|
||||
public virtual void AddChild(ProfileElement child, int? order = null)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException(GetType().Name);
|
||||
|
||||
lock (ChildrenList)
|
||||
{
|
||||
// Add to the end of the list
|
||||
@@ -169,6 +179,9 @@ namespace Artemis.Core.Models.Profile
|
||||
/// <param name="child">The profile element to remove</param>
|
||||
public virtual void RemoveChild(ProfileElement child)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException(GetType().Name);
|
||||
|
||||
lock (ChildrenList)
|
||||
{
|
||||
ChildrenList.Remove(child);
|
||||
|
||||
@@ -203,8 +203,6 @@ namespace Artemis.Core.Models.Profile
|
||||
// If we are at the end of the main timeline, wrap around back to the beginning
|
||||
if (DisplayContinuously && TimelinePosition >= mainSegmentEnd)
|
||||
TimelinePosition = StartSegmentLength + (mainSegmentEnd - TimelinePosition);
|
||||
else if (TimelinePosition >= TimelineLength)
|
||||
TimelinePosition = TimelineLength;
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -4,6 +4,7 @@ using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Linq.Expressions;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core.Exceptions;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.Core.Models.Surface;
|
||||
@@ -94,6 +95,11 @@ namespace Artemis.Core.Plugins.Abstract
|
||||
/// </summary>
|
||||
public abstract class ProfileModule : Module
|
||||
{
|
||||
protected ProfileModule()
|
||||
{
|
||||
OpacityOverride = 1;
|
||||
}
|
||||
|
||||
protected readonly List<PropertyInfo> HiddenPropertiesList = new List<PropertyInfo>();
|
||||
|
||||
/// <summary>
|
||||
@@ -113,6 +119,10 @@ namespace Artemis.Core.Plugins.Abstract
|
||||
{
|
||||
lock (this)
|
||||
{
|
||||
OpacityOverride = AnimatingProfileChange
|
||||
? Math.Max(0, OpacityOverride - 0.1)
|
||||
: Math.Min(1, OpacityOverride + 0.1);
|
||||
|
||||
// Update the profile
|
||||
if (!IsProfileUpdatingDisabled)
|
||||
ActiveProfile?.Update(deltaTime);
|
||||
@@ -129,6 +139,27 @@ namespace Artemis.Core.Plugins.Abstract
|
||||
}
|
||||
}
|
||||
|
||||
internal async Task ChangeActiveProfileAnimated(Profile profile, ArtemisSurface surface)
|
||||
{
|
||||
if (profile != null && profile.Module != this)
|
||||
throw new ArtemisCoreException($"Cannot activate a profile of module {profile.Module} on a module of plugin {PluginInfo}.");
|
||||
|
||||
|
||||
if (profile == ActiveProfile || AnimatingProfileChange)
|
||||
return;
|
||||
|
||||
AnimatingProfileChange = true;
|
||||
|
||||
while (OpacityOverride > 0)
|
||||
await Task.Delay(50);
|
||||
|
||||
ChangeActiveProfile(profile, surface);
|
||||
AnimatingProfileChange = false;
|
||||
|
||||
while (OpacityOverride < 1)
|
||||
await Task.Delay(50);
|
||||
}
|
||||
|
||||
internal void ChangeActiveProfile(Profile profile, ArtemisSurface surface)
|
||||
{
|
||||
if (profile != null && profile.Module != this)
|
||||
@@ -147,6 +178,16 @@ namespace Artemis.Core.Plugins.Abstract
|
||||
OnActiveProfileChanged();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Overrides the opacity of the root folder
|
||||
/// </summary>
|
||||
public double OpacityOverride { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Indicates whether or not a profile change is being animated
|
||||
/// </summary>
|
||||
public bool AnimatingProfileChange { get; private set; }
|
||||
|
||||
#region Events
|
||||
|
||||
public event EventHandler ActiveProfileChanged;
|
||||
|
||||
@@ -52,6 +52,8 @@ namespace Artemis.Core.Plugins.LayerBrush.Abstract
|
||||
{
|
||||
var artemisLed = Layer.Leds[index];
|
||||
var renderPoint = points[index * 2 + 1];
|
||||
if (!float.IsFinite(renderPoint.X) || !float.IsFinite(renderPoint.Y))
|
||||
continue;
|
||||
|
||||
// Let the brush determine the color
|
||||
ledPaint.Color = GetColor(artemisLed, renderPoint);
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -3,14 +3,17 @@ using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core.Events;
|
||||
using Artemis.Core.Exceptions;
|
||||
using Artemis.Core.JsonConverters;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.Core.Ninject;
|
||||
using Artemis.Core.Plugins.Abstract;
|
||||
using Artemis.Core.Plugins.Models;
|
||||
using Artemis.Core.Services.Interfaces;
|
||||
using Artemis.Core.Services.Storage.Interfaces;
|
||||
using Artemis.Core.Utilities;
|
||||
using Artemis.Storage;
|
||||
using Newtonsoft.Json;
|
||||
using RGB.NET.Core;
|
||||
@@ -35,6 +38,7 @@ namespace Artemis.Core.Services
|
||||
private readonly ISurfaceService _surfaceService;
|
||||
private List<BaseDataModelExpansion> _dataModelExpansions;
|
||||
private List<Module> _modules;
|
||||
private IntroAnimation _introAnimation;
|
||||
|
||||
// ReSharper disable once UnusedParameter.Local - Storage migration service is injected early to ensure it runs before anything else
|
||||
internal CoreService(ILogger logger, StorageMigrationService _, ISettingsService settingsService, IPluginService pluginService,
|
||||
@@ -90,11 +94,38 @@ namespace Artemis.Core.Services
|
||||
else
|
||||
_logger.Information("Initialized without an active surface entity");
|
||||
|
||||
PlayIntroAnimation();
|
||||
_profileService.ActivateLastActiveProfiles();
|
||||
|
||||
OnInitialized();
|
||||
}
|
||||
|
||||
private void PlayIntroAnimation()
|
||||
{
|
||||
FrameRendering += DrawOverlay;
|
||||
_introAnimation = new IntroAnimation(_logger, _profileService, _surfaceService);
|
||||
|
||||
// Draw a white overlay over the device
|
||||
void DrawOverlay(object sender, FrameRenderingEventArgs args)
|
||||
{
|
||||
if (_introAnimation == null)
|
||||
args.Canvas.Clear(new SKColor(0, 0, 0));
|
||||
else
|
||||
_introAnimation.Render(args.DeltaTime, args.Canvas, _rgbService.BitmapBrush.Bitmap.Info);
|
||||
}
|
||||
|
||||
var introLength = _introAnimation.AnimationProfile.GetAllLayers().Max(l => l.TimelineLength);
|
||||
|
||||
// Stop rendering after the profile finishes (take 1 second extra in case of slow updates)
|
||||
Task.Run(async () =>
|
||||
{
|
||||
await Task.Delay(introLength.Add(TimeSpan.FromSeconds(1)));
|
||||
FrameRendering -= DrawOverlay;
|
||||
|
||||
_introAnimation.AnimationProfile?.Dispose();
|
||||
_introAnimation = null;
|
||||
});
|
||||
}
|
||||
|
||||
public void SetMainWindowHandle(IntPtr handle)
|
||||
{
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core.Events;
|
||||
|
||||
namespace Artemis.Core.Services.Interfaces
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.Core.Plugins.Abstract;
|
||||
using Artemis.Core.Services.Interfaces;
|
||||
|
||||
namespace Artemis.Core.Services.Storage.Interfaces
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides access to profile storage and is responsible for activating default profiles
|
||||
/// </summary>
|
||||
public interface IProfileService : IArtemisService
|
||||
{
|
||||
/// <summary>
|
||||
@@ -18,14 +22,14 @@ namespace Artemis.Core.Services.Storage.Interfaces
|
||||
/// <param name="module">The profile module to create the profile for</param>
|
||||
/// <param name="name">The name of the new profile</param>
|
||||
/// <returns></returns>
|
||||
ProfileDescriptor CreateProfile(ProfileModule module, string name);
|
||||
ProfileDescriptor CreateProfileDescriptor(ProfileModule module, string name);
|
||||
|
||||
/// <summary>
|
||||
/// Gets a descriptor for each profile stored for the given <see cref="ProfileModule" />
|
||||
/// </summary>
|
||||
/// <param name="module">The module to return profile descriptors for</param>
|
||||
/// <returns></returns>
|
||||
List<ProfileDescriptor> GetProfiles(ProfileModule module);
|
||||
List<ProfileDescriptor> GetProfileDescriptors(ProfileModule module);
|
||||
|
||||
/// <summary>
|
||||
/// Writes the profile to persistent storage
|
||||
@@ -40,30 +44,53 @@ namespace Artemis.Core.Services.Storage.Interfaces
|
||||
/// <param name="profile">The profile to delete</param>
|
||||
void DeleteProfile(Profile profile);
|
||||
|
||||
/// <summary>
|
||||
/// Permanently deletes the profile described by the provided profile descriptor
|
||||
/// </summary>
|
||||
/// <param name="profileDescriptor">The descriptor pointing to the profile to delete</param>
|
||||
void DeleteProfile(ProfileDescriptor profileDescriptor);
|
||||
|
||||
/// <summary>
|
||||
/// Activates the profile described in the given <see cref="ProfileDescriptor" /> with the currently active surface
|
||||
/// </summary>
|
||||
/// <param name="profileDescriptor">The descriptor describing the profile to activate</param>
|
||||
Profile ActivateProfile(ProfileDescriptor profileDescriptor);
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously activates the profile described in the given <see cref="ProfileDescriptor" /> with the currently
|
||||
/// active surface using a fade animation
|
||||
/// </summary>
|
||||
/// <param name="profileDescriptor">The descriptor describing the profile to activate</param>
|
||||
Task<Profile> ActivateProfileAnimated(ProfileDescriptor profileDescriptor);
|
||||
|
||||
/// <summary>
|
||||
/// Clears the active profile on the given <see cref="ProfileModule" />
|
||||
/// </summary>
|
||||
/// <param name="module">The profile module to deactivate the active profile on</param>
|
||||
void ClearActiveProfile(ProfileModule module);
|
||||
|
||||
/// <summary>
|
||||
/// Asynchronously clears the active profile on the given <see cref="ProfileModule" /> using a fade animation
|
||||
/// </summary>
|
||||
/// <param name="module">The profile module to deactivate the active profile on</param>
|
||||
Task ClearActiveProfileAnimated(ProfileModule module);
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to restore the profile to the state it had before the last <see cref="UpdateProfile" /> call.
|
||||
/// </summary>
|
||||
/// <param name="selectedProfile"></param>
|
||||
/// <param name="module"></param>
|
||||
bool UndoUpdateProfile(Profile selectedProfile, ProfileModule module);
|
||||
/// <param name="profile"></param>
|
||||
bool UndoUpdateProfile(Profile profile);
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to restore the profile to the state it had before the last <see cref="UndoUpdateProfile" /> call.
|
||||
/// </summary>
|
||||
/// <param name="selectedProfile"></param>
|
||||
/// <param name="module"></param>
|
||||
bool RedoUpdateProfile(Profile selectedProfile, ProfileModule module);
|
||||
/// <param name="profile"></param>
|
||||
bool RedoUpdateProfile(Profile profile);
|
||||
|
||||
/// <summary>
|
||||
/// Prepares the profile for rendering. You should not need to call this, it is exposed for some niche usage in the core
|
||||
/// </summary>
|
||||
/// <param name="profile"></param>
|
||||
void InstantiateProfile(Profile profile);
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using Artemis.Core.Events;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.Core.Models.Surface;
|
||||
@@ -15,9 +16,6 @@ using Serilog;
|
||||
|
||||
namespace Artemis.Core.Services.Storage
|
||||
{
|
||||
/// <summary>
|
||||
/// Provides access to profile storage and is responsible for activating default profiles
|
||||
/// </summary>
|
||||
public class ProfileService : IProfileService
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
@@ -51,20 +49,13 @@ namespace Artemis.Core.Services.Storage
|
||||
}
|
||||
}
|
||||
|
||||
public List<ProfileDescriptor> GetProfiles(ProfileModule module)
|
||||
public List<ProfileDescriptor> GetProfileDescriptors(ProfileModule module)
|
||||
{
|
||||
var profileEntities = _profileRepository.GetByPluginGuid(module.PluginInfo.Guid);
|
||||
return profileEntities.Select(e => new ProfileDescriptor(module, e)).ToList();
|
||||
}
|
||||
|
||||
public ProfileDescriptor GetLastActiveProfile(ProfileModule module)
|
||||
{
|
||||
var moduleProfiles = _profileRepository.GetByPluginGuid(module.PluginInfo.Guid);
|
||||
var profileEntity = moduleProfiles.FirstOrDefault(p => p.IsActive) ?? moduleProfiles.FirstOrDefault();
|
||||
return profileEntity == null ? null : new ProfileDescriptor(module, profileEntity);
|
||||
}
|
||||
|
||||
public ProfileDescriptor CreateProfile(ProfileModule module, string name)
|
||||
public ProfileDescriptor CreateProfileDescriptor(ProfileModule module, string name)
|
||||
{
|
||||
var profileEntity = new ProfileEntity {Id = Guid.NewGuid(), Name = name, PluginGuid = module.PluginInfo.Guid};
|
||||
return new ProfileDescriptor(module, profileEntity);
|
||||
@@ -72,31 +63,59 @@ namespace Artemis.Core.Services.Storage
|
||||
|
||||
public Profile ActivateProfile(ProfileDescriptor profileDescriptor)
|
||||
{
|
||||
if (profileDescriptor.ProfileModule.ActiveProfile.EntityId == profileDescriptor.Id)
|
||||
if (profileDescriptor.ProfileModule.ActiveProfile?.EntityId == profileDescriptor.Id)
|
||||
return profileDescriptor.ProfileModule.ActiveProfile;
|
||||
|
||||
var profile = new Profile(profileDescriptor.ProfileModule, profileDescriptor.ProfileEntity);
|
||||
InitializeLayerProperties(profile);
|
||||
InstantiateLayers(profile);
|
||||
InstantiateFolders(profile);
|
||||
var profileEntity = _profileRepository.Get(profileDescriptor.Id);
|
||||
var profile = new Profile(profileDescriptor.ProfileModule, profileEntity);
|
||||
InstantiateProfile(profile);
|
||||
|
||||
profileDescriptor.ProfileModule.ChangeActiveProfile(profile, _surfaceService.ActiveSurface);
|
||||
return profile;
|
||||
}
|
||||
|
||||
public async Task<Profile> ActivateProfileAnimated(ProfileDescriptor profileDescriptor)
|
||||
{
|
||||
if (profileDescriptor.ProfileModule.ActiveProfile?.EntityId == profileDescriptor.Id)
|
||||
return profileDescriptor.ProfileModule.ActiveProfile;
|
||||
|
||||
var profileEntity = _profileRepository.Get(profileDescriptor.Id);
|
||||
var profile = new Profile(profileDescriptor.ProfileModule, profileEntity);
|
||||
InstantiateProfile(profile);
|
||||
|
||||
await profileDescriptor.ProfileModule.ChangeActiveProfileAnimated(profile, _surfaceService.ActiveSurface);
|
||||
return profile;
|
||||
}
|
||||
|
||||
public void ClearActiveProfile(ProfileModule module)
|
||||
{
|
||||
module.ChangeActiveProfile(null, _surfaceService.ActiveSurface);
|
||||
}
|
||||
|
||||
public async Task ClearActiveProfileAnimated(ProfileModule module)
|
||||
{
|
||||
await module.ChangeActiveProfileAnimated(null, _surfaceService.ActiveSurface);
|
||||
}
|
||||
|
||||
public void DeleteProfile(Profile profile)
|
||||
{
|
||||
_logger.Debug("Removing profile " + profile);
|
||||
|
||||
|
||||
// If the given profile is currently active, disable it first (this also disposes it)
|
||||
if (profile.Module.ActiveProfile == profile)
|
||||
profile.Module.ChangeActiveProfile(null, _surfaceService.ActiveSurface);
|
||||
else
|
||||
profile.Dispose();
|
||||
|
||||
_profileRepository.Remove(profile.ProfileEntity);
|
||||
}
|
||||
|
||||
public void DeleteProfile(ProfileDescriptor profileDescriptor)
|
||||
{
|
||||
var profileEntity = _profileRepository.Get(profileDescriptor.Id);
|
||||
_profileRepository.Remove(profileEntity);
|
||||
}
|
||||
|
||||
public void UpdateProfile(Profile profile, bool includeChildren)
|
||||
{
|
||||
_logger.Debug("Updating profile " + profile);
|
||||
@@ -116,46 +135,73 @@ namespace Artemis.Core.Services.Storage
|
||||
_profileRepository.Save(profile.ProfileEntity);
|
||||
}
|
||||
|
||||
public bool UndoUpdateProfile(Profile profile, ProfileModule module)
|
||||
public bool UndoUpdateProfile(Profile profile)
|
||||
{
|
||||
if (!profile.UndoStack.Any())
|
||||
// Keep the profile from being rendered by locking it
|
||||
lock (profile)
|
||||
{
|
||||
_logger.Debug("Undo profile update - Failed, undo stack empty");
|
||||
return false;
|
||||
}
|
||||
if (!profile.UndoStack.Any())
|
||||
{
|
||||
_logger.Debug("Undo profile update - Failed, undo stack empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
ActivateProfile(module, null);
|
||||
var top = profile.UndoStack.Pop();
|
||||
var memento = JsonConvert.SerializeObject(profile.ProfileEntity, MementoSettings);
|
||||
profile.RedoStack.Push(memento);
|
||||
profile.ProfileEntity = JsonConvert.DeserializeObject<ProfileEntity>(top, MementoSettings);
|
||||
profile.ApplyToProfile();
|
||||
ActivateProfile(module, profile);
|
||||
var top = profile.UndoStack.Pop();
|
||||
var memento = JsonConvert.SerializeObject(profile.ProfileEntity, MementoSettings);
|
||||
profile.RedoStack.Push(memento);
|
||||
profile.ProfileEntity = JsonConvert.DeserializeObject<ProfileEntity>(top, MementoSettings);
|
||||
|
||||
profile.ApplyToProfile();
|
||||
InstantiateProfile(profile);
|
||||
}
|
||||
|
||||
_logger.Debug("Undo profile update - Success");
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool RedoUpdateProfile(Profile profile, ProfileModule module)
|
||||
public bool RedoUpdateProfile(Profile profile)
|
||||
{
|
||||
if (!profile.RedoStack.Any())
|
||||
// Keep the profile from being rendered by locking it
|
||||
lock (profile)
|
||||
{
|
||||
_logger.Debug("Redo profile update - Failed, redo empty");
|
||||
return false;
|
||||
if (!profile.RedoStack.Any())
|
||||
{
|
||||
_logger.Debug("Redo profile update - Failed, redo empty");
|
||||
return false;
|
||||
}
|
||||
|
||||
var top = profile.RedoStack.Pop();
|
||||
var memento = JsonConvert.SerializeObject(profile.ProfileEntity, MementoSettings);
|
||||
profile.UndoStack.Push(memento);
|
||||
profile.ProfileEntity = JsonConvert.DeserializeObject<ProfileEntity>(top, MementoSettings);
|
||||
|
||||
profile.ApplyToProfile();
|
||||
InstantiateProfile(profile);
|
||||
|
||||
_logger.Debug("Redo profile update - Success");
|
||||
return true;
|
||||
}
|
||||
|
||||
ActivateProfile(module, null);
|
||||
var top = profile.RedoStack.Pop();
|
||||
var memento = JsonConvert.SerializeObject(profile.ProfileEntity, MementoSettings);
|
||||
profile.UndoStack.Push(memento);
|
||||
profile.ProfileEntity = JsonConvert.DeserializeObject<ProfileEntity>(top, MementoSettings);
|
||||
profile.ApplyToProfile();
|
||||
ActivateProfile(module, profile);
|
||||
|
||||
_logger.Debug("Redo profile update - Success");
|
||||
return true;
|
||||
}
|
||||
|
||||
public ProfileDescriptor GetLastActiveProfile(ProfileModule module)
|
||||
{
|
||||
var moduleProfiles = _profileRepository.GetByPluginGuid(module.PluginInfo.Guid);
|
||||
var profileEntity = moduleProfiles.FirstOrDefault(p => p.IsActive) ?? moduleProfiles.FirstOrDefault();
|
||||
return profileEntity == null ? null : new ProfileDescriptor(module, profileEntity);
|
||||
}
|
||||
|
||||
public void InstantiateProfile(Profile profile)
|
||||
{
|
||||
profile.PopulateLeds(_surfaceService.ActiveSurface);
|
||||
InitializeLayerProperties(profile);
|
||||
InstantiateLayers(profile);
|
||||
InstantiateFolders(profile);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the properties on the layers of the given profile
|
||||
/// </summary>
|
||||
/// <param name="profile"></param>
|
||||
private void InitializeLayerProperties(Profile profile)
|
||||
{
|
||||
foreach (var layer in profile.GetAllLayers())
|
||||
@@ -167,6 +213,9 @@ namespace Artemis.Core.Services.Storage
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates all plugin-related classes on the folders of the given profile
|
||||
/// </summary>
|
||||
private void InstantiateFolders(Profile profile)
|
||||
{
|
||||
foreach (var folder in profile.GetAllFolders())
|
||||
@@ -182,6 +231,9 @@ namespace Artemis.Core.Services.Storage
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates all plugin-related classes on the layers of the given profile
|
||||
/// </summary>
|
||||
private void InstantiateLayers(Profile profile)
|
||||
{
|
||||
foreach (var layer in profile.GetAllLayers())
|
||||
@@ -204,6 +256,10 @@ namespace Artemis.Core.Services.Storage
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Populates all missing LEDs on all currently active profiles
|
||||
/// </summary>
|
||||
/// <param name="surface"></param>
|
||||
private void ActiveProfilesPopulateLeds(ArtemisSurface surface)
|
||||
{
|
||||
var profileModules = _pluginService.GetPluginsOfType<ProfileModule>();
|
||||
@@ -211,6 +267,10 @@ namespace Artemis.Core.Services.Storage
|
||||
profileModule.ActiveProfile.PopulateLeds(surface);
|
||||
}
|
||||
|
||||
|
||||
/// <summary>
|
||||
/// Instantiates all missing plugin-related classes on the profile trees of all currently active profiles
|
||||
/// </summary>
|
||||
private void ActiveProfilesInstantiatePlugins()
|
||||
{
|
||||
var profileModules = _pluginService.GetPluginsOfType<ProfileModule>();
|
||||
@@ -242,8 +302,8 @@ namespace Artemis.Core.Services.Storage
|
||||
ActiveProfilesInstantiatePlugins();
|
||||
else if (e.PluginInfo.Instance is ProfileModule profileModule)
|
||||
{
|
||||
var activeProfile = GetActiveProfile(profileModule);
|
||||
ActivateProfile(profileModule, activeProfile);
|
||||
var activeProfile = GetLastActiveProfile(profileModule);
|
||||
ActivateProfile(activeProfile);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Artemis.Core.Extensions;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.Core.Models.Surface;
|
||||
using Artemis.Core.Plugins.Abstract;
|
||||
using Artemis.Core.Plugins.Abstract.ViewModels;
|
||||
using Artemis.Core.Plugins.LayerBrush;
|
||||
using Artemis.Core.Services.Interfaces;
|
||||
using Artemis.Core.Services.Storage.Interfaces;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Serilog;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core.Utilities
|
||||
{
|
||||
internal class IntroAnimation
|
||||
{
|
||||
private readonly ILogger _logger;
|
||||
private readonly IProfileService _profileService;
|
||||
private readonly ISurfaceService _surfaceService;
|
||||
|
||||
public IntroAnimation(ILogger logger, IProfileService profileService, ISurfaceService surfaceService)
|
||||
{
|
||||
_logger = logger;
|
||||
_profileService = profileService;
|
||||
_surfaceService = surfaceService;
|
||||
CreateIntroProfile();
|
||||
}
|
||||
|
||||
private void CreateIntroProfile()
|
||||
{
|
||||
try
|
||||
{
|
||||
// Load the intro profile from JSON into a ProfileEntity
|
||||
var json = File.ReadAllText(Path.Combine(Constants.ApplicationFolder, "Resources", "intro-profile.json"));
|
||||
var profileEntity = JsonConvert.DeserializeObject<ProfileEntity>(json);
|
||||
// Inject every LED on the surface into each layer
|
||||
foreach (var profileEntityLayer in profileEntity.Layers)
|
||||
{
|
||||
profileEntityLayer.Leds.AddRange(_surfaceService.ActiveSurface.Devices.SelectMany(d => d.Leds).Select(l => new LedEntity()
|
||||
{
|
||||
DeviceIdentifier = l.Device.RgbDevice.GetDeviceIdentifier(),
|
||||
LedName = l.RgbLed.Id.ToString(),
|
||||
}));
|
||||
}
|
||||
|
||||
var profile = new Profile(new DummyModule(), profileEntity);
|
||||
profile.Activate(_surfaceService.ActiveSurface);
|
||||
|
||||
_profileService.InstantiateProfile(profile);
|
||||
AnimationProfile = profile;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_logger.Warning(e, "Failed to load intro profile");
|
||||
}
|
||||
}
|
||||
|
||||
public Profile AnimationProfile { get; set; }
|
||||
|
||||
public void Render(double deltaTime, SKCanvas canvas, SKImageInfo bitmapInfo)
|
||||
{
|
||||
if (AnimationProfile == null)
|
||||
return;
|
||||
|
||||
AnimationProfile.Update(deltaTime);
|
||||
AnimationProfile.Render(deltaTime, canvas, bitmapInfo);
|
||||
}
|
||||
}
|
||||
|
||||
internal class DummyModule : ProfileModule
|
||||
{
|
||||
public override void EnablePlugin()
|
||||
{
|
||||
}
|
||||
|
||||
public override void DisablePlugin()
|
||||
{
|
||||
}
|
||||
|
||||
public override IEnumerable<ModuleViewModel> GetViewModels()
|
||||
{
|
||||
return new List<ModuleViewModel>();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user