mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Profiles - Finished dispose implementation
Profiles - Added transition between active profiles Core - Added startup animation
This commit is contained in:
parent
c0bdd8cf26
commit
d955bc8635
@ -70,4 +70,9 @@
|
|||||||
<HintPath>..\..\..\RGB.NET\bin\netstandard2.0\RGB.NET.Groups.dll</HintPath>
|
<HintPath>..\..\..\RGB.NET\bin\netstandard2.0\RGB.NET.Groups.dll</HintPath>
|
||||||
</Reference>
|
</Reference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Update="Resources\intro-profile.json">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</None>
|
||||||
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@ -2,6 +2,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Artemis.Core.Plugins.LayerEffect.Abstract;
|
using Artemis.Core.Plugins.LayerEffect.Abstract;
|
||||||
|
using Artemis.Core.Utilities;
|
||||||
using Artemis.Storage.Entities.Profile;
|
using Artemis.Storage.Entities.Profile;
|
||||||
using Artemis.Storage.Entities.Profile.Abstract;
|
using Artemis.Storage.Entities.Profile.Abstract;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
@ -61,9 +62,13 @@ namespace Artemis.Core.Models.Profile
|
|||||||
|
|
||||||
internal FolderEntity FolderEntity { get; set; }
|
internal FolderEntity FolderEntity { get; set; }
|
||||||
internal override RenderElementEntity RenderElementEntity => FolderEntity;
|
internal override RenderElementEntity RenderElementEntity => FolderEntity;
|
||||||
|
public bool IsRootFolder => Parent == Profile;
|
||||||
|
|
||||||
public override void Update(double deltaTime)
|
public override void Update(double deltaTime)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Folder");
|
||||||
|
|
||||||
if (!Enabled)
|
if (!Enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -89,6 +94,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
|
|
||||||
public override void OverrideProgress(TimeSpan timeOverride, bool stickToMainSegment)
|
public override void OverrideProgress(TimeSpan timeOverride, bool stickToMainSegment)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Folder");
|
||||||
|
|
||||||
if (!Enabled)
|
if (!Enabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -125,6 +133,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
|
|
||||||
public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo)
|
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))
|
if (Path == null || !Enabled || !Children.Any(c => c.Enabled))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -172,6 +183,13 @@ namespace Artemis.Core.Models.Profile
|
|||||||
profileElement.Render(deltaTime, folderCanvas, _folderBitmap.Info);
|
profileElement.Render(deltaTime, folderCanvas, _folderBitmap.Info);
|
||||||
folderCanvas.Restore();
|
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))
|
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
||||||
baseLayerEffect.PostProcess(canvas, canvasInfo, folderPath, folderPaint);
|
baseLayerEffect.PostProcess(canvas, canvasInfo, folderPath, folderPaint);
|
||||||
@ -187,6 +205,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public Folder AddFolder(string name)
|
public Folder AddFolder(string name)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Folder");
|
||||||
|
|
||||||
var folder = new Folder(Profile, this, name) {Order = Children.LastOrDefault()?.Order ?? 1};
|
var folder = new Folder(Profile, this, name) {Order = Children.LastOrDefault()?.Order ?? 1};
|
||||||
AddChild(folder);
|
AddChild(folder);
|
||||||
return folder;
|
return folder;
|
||||||
@ -195,6 +216,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void AddChild(ProfileElement child, int? order = null)
|
public override void AddChild(ProfileElement child, int? order = null)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Folder");
|
||||||
|
|
||||||
base.AddChild(child, order);
|
base.AddChild(child, order);
|
||||||
CalculateRenderProperties();
|
CalculateRenderProperties();
|
||||||
}
|
}
|
||||||
@ -202,6 +226,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void RemoveChild(ProfileElement child)
|
public override void RemoveChild(ProfileElement child)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Folder");
|
||||||
|
|
||||||
base.RemoveChild(child);
|
base.RemoveChild(child);
|
||||||
CalculateRenderProperties();
|
CalculateRenderProperties();
|
||||||
}
|
}
|
||||||
@ -213,6 +240,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
|
|
||||||
public void CalculateRenderProperties()
|
public void CalculateRenderProperties()
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Folder");
|
||||||
|
|
||||||
var path = new SKPath {FillType = SKPathFillType.Winding};
|
var path = new SKPath {FillType = SKPathFillType.Winding};
|
||||||
foreach (var child in Children)
|
foreach (var child in Children)
|
||||||
{
|
{
|
||||||
@ -234,16 +264,27 @@ namespace Artemis.Core.Models.Profile
|
|||||||
if (!disposing)
|
if (!disposing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_folderBitmap?.Dispose();
|
|
||||||
foreach (var baseLayerEffect in LayerEffects)
|
foreach (var baseLayerEffect in LayerEffects)
|
||||||
baseLayerEffect.Dispose();
|
baseLayerEffect.Dispose();
|
||||||
|
_layerEffects.Clear();
|
||||||
|
|
||||||
foreach (var profileElement in Children)
|
foreach (var profileElement in Children)
|
||||||
profileElement.Dispose();
|
profileElement.Dispose();
|
||||||
|
ChildrenList.Clear();
|
||||||
|
|
||||||
|
_folderBitmap?.Dispose();
|
||||||
|
_folderBitmap = null;
|
||||||
|
|
||||||
|
Profile = null;
|
||||||
|
_disposed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal override void ApplyToEntity()
|
internal override void ApplyToEntity()
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Folder");
|
||||||
|
|
||||||
FolderEntity.Id = EntityId;
|
FolderEntity.Id = EntityId;
|
||||||
FolderEntity.ParentId = Parent?.EntityId ?? new Guid();
|
FolderEntity.ParentId = Parent?.EntityId ?? new Guid();
|
||||||
|
|
||||||
@ -262,16 +303,6 @@ namespace Artemis.Core.Models.Profile
|
|||||||
DisplayConditionGroup?.ApplyToEntity();
|
DisplayConditionGroup?.ApplyToEntity();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Deactivate()
|
|
||||||
{
|
|
||||||
_folderBitmap?.Dispose();
|
|
||||||
_folderBitmap = null;
|
|
||||||
|
|
||||||
var layerEffects = new List<BaseLayerEffect>(LayerEffects);
|
|
||||||
foreach (var baseLayerEffect in layerEffects)
|
|
||||||
DeactivateLayerEffect(baseLayerEffect);
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Events
|
#region Events
|
||||||
|
|
||||||
public event EventHandler RenderPropertiesUpdated;
|
public event EventHandler RenderPropertiesUpdated;
|
||||||
|
|||||||
@ -126,6 +126,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override List<BaseLayerPropertyKeyframe> GetAllKeyframes()
|
public override List<BaseLayerPropertyKeyframe> GetAllKeyframes()
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Layer");
|
||||||
|
|
||||||
var keyframes = base.GetAllKeyframes();
|
var keyframes = base.GetAllKeyframes();
|
||||||
|
|
||||||
foreach (var baseLayerProperty in General.GetAllLayerProperties())
|
foreach (var baseLayerProperty in General.GetAllLayerProperties())
|
||||||
@ -143,22 +146,36 @@ namespace Artemis.Core.Models.Profile
|
|||||||
|
|
||||||
protected override void Dispose(bool disposing)
|
protected override void Dispose(bool disposing)
|
||||||
{
|
{
|
||||||
if (!disposing)
|
if (!disposing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
_general?.Dispose();
|
_disposed = true;
|
||||||
_layerBitmap?.Dispose();
|
|
||||||
|
// Brush first in case it depends on any of the other disposables during it's own disposal
|
||||||
_layerBrush?.Dispose();
|
_layerBrush?.Dispose();
|
||||||
_transform?.Dispose();
|
_layerBrush = null;
|
||||||
|
|
||||||
foreach (var baseLayerEffect in LayerEffects)
|
foreach (var baseLayerEffect in LayerEffects)
|
||||||
baseLayerEffect.Dispose();
|
baseLayerEffect.Dispose();
|
||||||
|
_layerEffects.Clear();
|
||||||
|
|
||||||
|
_general?.Dispose();
|
||||||
|
_general = null;
|
||||||
|
_layerBitmap?.Dispose();
|
||||||
|
_layerBitmap = null;
|
||||||
|
_transform?.Dispose();
|
||||||
|
_transform = null;
|
||||||
|
|
||||||
|
Profile = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Storage
|
#region Storage
|
||||||
|
|
||||||
internal override void ApplyToEntity()
|
internal override void ApplyToEntity()
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Layer");
|
||||||
|
|
||||||
// Properties
|
// Properties
|
||||||
LayerEntity.Id = EntityId;
|
LayerEntity.Id = EntityId;
|
||||||
LayerEntity.ParentId = Parent?.EntityId ?? new Guid();
|
LayerEntity.ParentId = Parent?.EntityId ?? new Guid();
|
||||||
@ -231,6 +248,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Update(double deltaTime)
|
public override void Update(double deltaTime)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Layer");
|
||||||
|
|
||||||
if (!Enabled || LayerBrush?.BaseProperties == null || !LayerBrush.BaseProperties.PropertiesInitialized)
|
if (!Enabled || LayerBrush?.BaseProperties == null || !LayerBrush.BaseProperties.PropertiesInitialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -259,6 +279,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
|
|
||||||
public override void OverrideProgress(TimeSpan timeOverride, bool stickToMainSegment)
|
public override void OverrideProgress(TimeSpan timeOverride, bool stickToMainSegment)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Layer");
|
||||||
|
|
||||||
if (!Enabled || LayerBrush?.BaseProperties == null || !LayerBrush.BaseProperties.PropertiesInitialized)
|
if (!Enabled || LayerBrush?.BaseProperties == null || !LayerBrush.BaseProperties.PropertiesInitialized)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -268,9 +291,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
{
|
{
|
||||||
if (!DisplayContinuously)
|
if (!DisplayContinuously)
|
||||||
{
|
{
|
||||||
var position = timeOverride + StartSegmentLength;
|
TimelinePosition = StartSegmentLength + timeOverride;
|
||||||
if (position > StartSegmentLength + EndSegmentLength)
|
|
||||||
TimelinePosition = StartSegmentLength + EndSegmentLength;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -301,6 +322,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo)
|
public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Layer");
|
||||||
|
|
||||||
if (!Enabled || TimelinePosition > TimelineLength)
|
if (!Enabled || TimelinePosition > TimelineLength)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -424,6 +448,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
|
|
||||||
internal void CalculateRenderProperties()
|
internal void CalculateRenderProperties()
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Layer");
|
||||||
|
|
||||||
if (!Leds.Any())
|
if (!Leds.Any())
|
||||||
Path = new SKPath();
|
Path = new SKPath();
|
||||||
else
|
else
|
||||||
@ -448,6 +475,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
|
|
||||||
internal SKPoint GetLayerAnchorPosition(SKPath layerPath, bool zeroBased = false)
|
internal SKPoint GetLayerAnchorPosition(SKPath layerPath, bool zeroBased = false)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Layer");
|
||||||
|
|
||||||
var positionProperty = Transform.Position.CurrentValue;
|
var positionProperty = Transform.Position.CurrentValue;
|
||||||
|
|
||||||
// Start at the center of the shape
|
// Start at the center of the shape
|
||||||
@ -469,6 +499,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
/// <param name="path"></param>
|
/// <param name="path"></param>
|
||||||
public void IncludePathInTranslation(SKPath path, bool zeroBased)
|
public void IncludePathInTranslation(SKPath path, bool zeroBased)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Layer");
|
||||||
|
|
||||||
var sizeProperty = Transform.Scale.CurrentValue;
|
var sizeProperty = Transform.Scale.CurrentValue;
|
||||||
var rotationProperty = Transform.Rotation.CurrentValue;
|
var rotationProperty = Transform.Rotation.CurrentValue;
|
||||||
|
|
||||||
@ -498,6 +531,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void ExcludePathFromTranslation(SKPath path, bool zeroBased)
|
public void ExcludePathFromTranslation(SKPath path, bool zeroBased)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Layer");
|
||||||
|
|
||||||
var sizeProperty = Transform.Scale.CurrentValue;
|
var sizeProperty = Transform.Scale.CurrentValue;
|
||||||
var rotationProperty = Transform.Rotation.CurrentValue;
|
var rotationProperty = Transform.Rotation.CurrentValue;
|
||||||
|
|
||||||
@ -531,6 +567,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
/// <returns>The number of transformations applied</returns>
|
/// <returns>The number of transformations applied</returns>
|
||||||
public int ExcludeCanvasFromTranslation(SKCanvas canvas, bool zeroBased)
|
public int ExcludeCanvasFromTranslation(SKCanvas canvas, bool zeroBased)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Layer");
|
||||||
|
|
||||||
var sizeProperty = Transform.Scale.CurrentValue;
|
var sizeProperty = Transform.Scale.CurrentValue;
|
||||||
var rotationProperty = Transform.Rotation.CurrentValue;
|
var rotationProperty = Transform.Rotation.CurrentValue;
|
||||||
|
|
||||||
@ -568,6 +607,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
/// <param name="led">The LED to add</param>
|
/// <param name="led">The LED to add</param>
|
||||||
public void AddLed(ArtemisLed led)
|
public void AddLed(ArtemisLed led)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Layer");
|
||||||
|
|
||||||
_leds.Add(led);
|
_leds.Add(led);
|
||||||
CalculateRenderProperties();
|
CalculateRenderProperties();
|
||||||
}
|
}
|
||||||
@ -578,6 +620,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
/// <param name="leds">The LEDs to add</param>
|
/// <param name="leds">The LEDs to add</param>
|
||||||
public void AddLeds(IEnumerable<ArtemisLed> leds)
|
public void AddLeds(IEnumerable<ArtemisLed> leds)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Layer");
|
||||||
|
|
||||||
_leds.AddRange(leds);
|
_leds.AddRange(leds);
|
||||||
CalculateRenderProperties();
|
CalculateRenderProperties();
|
||||||
}
|
}
|
||||||
@ -588,6 +633,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
/// <param name="led">The LED to remove</param>
|
/// <param name="led">The LED to remove</param>
|
||||||
public void RemoveLed(ArtemisLed led)
|
public void RemoveLed(ArtemisLed led)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Layer");
|
||||||
|
|
||||||
_leds.Remove(led);
|
_leds.Remove(led);
|
||||||
CalculateRenderProperties();
|
CalculateRenderProperties();
|
||||||
}
|
}
|
||||||
@ -597,12 +645,18 @@ namespace Artemis.Core.Models.Profile
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void ClearLeds()
|
public void ClearLeds()
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Layer");
|
||||||
|
|
||||||
_leds.Clear();
|
_leds.Clear();
|
||||||
CalculateRenderProperties();
|
CalculateRenderProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void PopulateLeds(ArtemisSurface surface)
|
internal void PopulateLeds(ArtemisSurface surface)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Layer");
|
||||||
|
|
||||||
var leds = new List<ArtemisLed>();
|
var leds = new List<ArtemisLed>();
|
||||||
|
|
||||||
// Get the surface LEDs for this layer
|
// Get the surface LEDs for this layer
|
||||||
@ -623,17 +677,6 @@ namespace Artemis.Core.Models.Profile
|
|||||||
|
|
||||||
#region Activation
|
#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()
|
internal void DeactivateLayerBrush()
|
||||||
{
|
{
|
||||||
if (LayerBrush == null)
|
if (LayerBrush == null)
|
||||||
|
|||||||
@ -28,5 +28,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
protected override void EnableProperties()
|
protected override void EnableProperties()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void DisableProperties()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -110,6 +110,8 @@ namespace Artemis.Core.Models.Profile
|
|||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
DisableProperties();
|
DisableProperties();
|
||||||
|
foreach (var layerPropertyGroup in _layerPropertyGroups)
|
||||||
|
layerPropertyGroup.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -30,5 +30,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
protected override void EnableProperties()
|
protected override void EnableProperties()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void DisableProperties()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -57,6 +57,8 @@ namespace Artemis.Core.Models.Profile
|
|||||||
{
|
{
|
||||||
lock (this)
|
lock (this)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Profile");
|
||||||
if (!IsActivated)
|
if (!IsActivated)
|
||||||
throw new ArtemisCoreException($"Cannot update inactive profile: {this}");
|
throw new ArtemisCoreException($"Cannot update inactive profile: {this}");
|
||||||
|
|
||||||
@ -69,6 +71,8 @@ namespace Artemis.Core.Models.Profile
|
|||||||
{
|
{
|
||||||
lock (this)
|
lock (this)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Profile");
|
||||||
if (!IsActivated)
|
if (!IsActivated)
|
||||||
throw new ArtemisCoreException($"Cannot render inactive profile: {this}");
|
throw new ArtemisCoreException($"Cannot render inactive profile: {this}");
|
||||||
|
|
||||||
@ -79,21 +83,26 @@ namespace Artemis.Core.Models.Profile
|
|||||||
|
|
||||||
public Folder GetRootFolder()
|
public Folder GetRootFolder()
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Profile");
|
||||||
|
|
||||||
return (Folder) Children.Single();
|
return (Folder) Children.Single();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ApplyToProfile()
|
public void ApplyToProfile()
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Profile");
|
||||||
|
|
||||||
Name = ProfileEntity.Name;
|
Name = ProfileEntity.Name;
|
||||||
|
|
||||||
lock (ChildrenList)
|
lock (ChildrenList)
|
||||||
{
|
{
|
||||||
foreach (var folder in GetAllFolders())
|
// Remove the old profile tree
|
||||||
folder.Deactivate();
|
foreach (var profileElement in Children)
|
||||||
foreach (var layer in GetAllLayers())
|
profileElement.Dispose();
|
||||||
layer.Deactivate();
|
|
||||||
|
|
||||||
ChildrenList.Clear();
|
ChildrenList.Clear();
|
||||||
|
|
||||||
// Populate the profile starting at the root, the rest is populated recursively
|
// Populate the profile starting at the root, the rest is populated recursively
|
||||||
var rootFolder = ProfileEntity.Folders.FirstOrDefault(f => f.ParentId == EntityId);
|
var rootFolder = ProfileEntity.Folders.FirstOrDefault(f => f.ParentId == EntityId);
|
||||||
if (rootFolder == null)
|
if (rootFolder == null)
|
||||||
@ -113,13 +122,21 @@ namespace Artemis.Core.Models.Profile
|
|||||||
if (!disposing)
|
if (!disposing)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Deactivate();
|
OnDeactivating();
|
||||||
|
|
||||||
foreach (var profileElement in Children)
|
foreach (var profileElement in Children)
|
||||||
profileElement.Dispose();
|
profileElement.Dispose();
|
||||||
|
ChildrenList.Clear();
|
||||||
|
|
||||||
|
IsActivated = false;
|
||||||
|
_disposed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override void ApplyToEntity()
|
internal override void ApplyToEntity()
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Profile");
|
||||||
|
|
||||||
ProfileEntity.Id = EntityId;
|
ProfileEntity.Id = EntityId;
|
||||||
ProfileEntity.PluginGuid = Module.PluginInfo.Guid;
|
ProfileEntity.PluginGuid = Module.PluginInfo.Guid;
|
||||||
ProfileEntity.Name = Name;
|
ProfileEntity.Name = Name;
|
||||||
@ -139,6 +156,8 @@ namespace Artemis.Core.Models.Profile
|
|||||||
{
|
{
|
||||||
lock (this)
|
lock (this)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Profile");
|
||||||
if (IsActivated)
|
if (IsActivated)
|
||||||
return;
|
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)
|
internal void PopulateLeds(ArtemisSurface surface)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException("Profile");
|
||||||
|
|
||||||
foreach (var layer in GetAllLayers())
|
foreach (var layer in GetAllLayers())
|
||||||
layer.PopulateLeds(surface);
|
layer.PopulateLeds(surface);
|
||||||
}
|
}
|
||||||
@ -174,7 +179,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
#region Events
|
#region Events
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs when the profile is being activated.
|
/// Occurs when the profile has been activated.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler Activated;
|
public event EventHandler Activated;
|
||||||
|
|
||||||
@ -188,7 +193,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
Activated?.Invoke(this, EventArgs.Empty);
|
Activated?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnDeactivated()
|
private void OnDeactivating()
|
||||||
{
|
{
|
||||||
Deactivated?.Invoke(this, EventArgs.Empty);
|
Deactivated?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -9,16 +9,16 @@ namespace Artemis.Core.Models.Profile
|
|||||||
internal ProfileDescriptor(ProfileModule profileModule, ProfileEntity profileEntity)
|
internal ProfileDescriptor(ProfileModule profileModule, ProfileEntity profileEntity)
|
||||||
{
|
{
|
||||||
ProfileModule = profileModule;
|
ProfileModule = profileModule;
|
||||||
ProfileEntity = profileEntity;
|
|
||||||
|
|
||||||
Id = profileEntity.Id;
|
Id = profileEntity.Id;
|
||||||
Name = profileEntity.Name;
|
Name = profileEntity.Name;
|
||||||
|
IsLastActiveProfile = profileEntity.IsActive;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsLastActiveProfile { get; set; }
|
||||||
|
|
||||||
public Guid Id { get; }
|
public Guid Id { get; }
|
||||||
public ProfileModule ProfileModule { get; }
|
public ProfileModule ProfileModule { get; }
|
||||||
public string Name { get; }
|
public string Name { get; }
|
||||||
|
|
||||||
internal ProfileEntity ProfileEntity { get; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -22,6 +22,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected bool _disposed;
|
||||||
private bool _enabled;
|
private bool _enabled;
|
||||||
private Guid _entityId;
|
private Guid _entityId;
|
||||||
private string _name;
|
private string _name;
|
||||||
@ -98,6 +99,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
|
|
||||||
public List<Folder> GetAllFolders()
|
public List<Folder> GetAllFolders()
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException(GetType().Name);
|
||||||
|
|
||||||
var folders = new List<Folder>();
|
var folders = new List<Folder>();
|
||||||
foreach (var childFolder in Children.Where(c => c is Folder).Cast<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()
|
public List<Layer> GetAllLayers()
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException(GetType().Name);
|
||||||
|
|
||||||
var layers = new List<Layer>();
|
var layers = new List<Layer>();
|
||||||
|
|
||||||
// Add all layers in this element
|
// 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>
|
/// <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)
|
public virtual void AddChild(ProfileElement child, int? order = null)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException(GetType().Name);
|
||||||
|
|
||||||
lock (ChildrenList)
|
lock (ChildrenList)
|
||||||
{
|
{
|
||||||
// Add to the end of the list
|
// 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>
|
/// <param name="child">The profile element to remove</param>
|
||||||
public virtual void RemoveChild(ProfileElement child)
|
public virtual void RemoveChild(ProfileElement child)
|
||||||
{
|
{
|
||||||
|
if (_disposed)
|
||||||
|
throw new ObjectDisposedException(GetType().Name);
|
||||||
|
|
||||||
lock (ChildrenList)
|
lock (ChildrenList)
|
||||||
{
|
{
|
||||||
ChildrenList.Remove(child);
|
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 we are at the end of the main timeline, wrap around back to the beginning
|
||||||
if (DisplayContinuously && TimelinePosition >= mainSegmentEnd)
|
if (DisplayContinuously && TimelinePosition >= mainSegmentEnd)
|
||||||
TimelinePosition = StartSegmentLength + (mainSegmentEnd - TimelinePosition);
|
TimelinePosition = StartSegmentLength + (mainSegmentEnd - TimelinePosition);
|
||||||
else if (TimelinePosition >= TimelineLength)
|
|
||||||
TimelinePosition = TimelineLength;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|||||||
@ -4,6 +4,7 @@ using System.Collections.ObjectModel;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Linq.Expressions;
|
using System.Linq.Expressions;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core.Exceptions;
|
using Artemis.Core.Exceptions;
|
||||||
using Artemis.Core.Models.Profile;
|
using Artemis.Core.Models.Profile;
|
||||||
using Artemis.Core.Models.Surface;
|
using Artemis.Core.Models.Surface;
|
||||||
@ -94,6 +95,11 @@ namespace Artemis.Core.Plugins.Abstract
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class ProfileModule : Module
|
public abstract class ProfileModule : Module
|
||||||
{
|
{
|
||||||
|
protected ProfileModule()
|
||||||
|
{
|
||||||
|
OpacityOverride = 1;
|
||||||
|
}
|
||||||
|
|
||||||
protected readonly List<PropertyInfo> HiddenPropertiesList = new List<PropertyInfo>();
|
protected readonly List<PropertyInfo> HiddenPropertiesList = new List<PropertyInfo>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -113,6 +119,10 @@ namespace Artemis.Core.Plugins.Abstract
|
|||||||
{
|
{
|
||||||
lock (this)
|
lock (this)
|
||||||
{
|
{
|
||||||
|
OpacityOverride = AnimatingProfileChange
|
||||||
|
? Math.Max(0, OpacityOverride - 0.1)
|
||||||
|
: Math.Min(1, OpacityOverride + 0.1);
|
||||||
|
|
||||||
// Update the profile
|
// Update the profile
|
||||||
if (!IsProfileUpdatingDisabled)
|
if (!IsProfileUpdatingDisabled)
|
||||||
ActiveProfile?.Update(deltaTime);
|
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)
|
internal void ChangeActiveProfile(Profile profile, ArtemisSurface surface)
|
||||||
{
|
{
|
||||||
if (profile != null && profile.Module != this)
|
if (profile != null && profile.Module != this)
|
||||||
@ -147,6 +178,16 @@ namespace Artemis.Core.Plugins.Abstract
|
|||||||
OnActiveProfileChanged();
|
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
|
#region Events
|
||||||
|
|
||||||
public event EventHandler ActiveProfileChanged;
|
public event EventHandler ActiveProfileChanged;
|
||||||
|
|||||||
@ -52,6 +52,8 @@ namespace Artemis.Core.Plugins.LayerBrush.Abstract
|
|||||||
{
|
{
|
||||||
var artemisLed = Layer.Leds[index];
|
var artemisLed = Layer.Leds[index];
|
||||||
var renderPoint = points[index * 2 + 1];
|
var renderPoint = points[index * 2 + 1];
|
||||||
|
if (!float.IsFinite(renderPoint.X) || !float.IsFinite(renderPoint.Y))
|
||||||
|
continue;
|
||||||
|
|
||||||
// Let the brush determine the color
|
// Let the brush determine the color
|
||||||
ledPaint.Color = GetColor(artemisLed, renderPoint);
|
ledPaint.Color = GetColor(artemisLed, renderPoint);
|
||||||
|
|||||||
1045
src/Artemis.Core/Resources/intro-profile.json
Normal file
1045
src/Artemis.Core/Resources/intro-profile.json
Normal file
File diff suppressed because it is too large
Load Diff
@ -3,14 +3,17 @@ using System.Collections.Generic;
|
|||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core.Events;
|
using Artemis.Core.Events;
|
||||||
using Artemis.Core.Exceptions;
|
using Artemis.Core.Exceptions;
|
||||||
using Artemis.Core.JsonConverters;
|
using Artemis.Core.JsonConverters;
|
||||||
|
using Artemis.Core.Models.Profile;
|
||||||
using Artemis.Core.Ninject;
|
using Artemis.Core.Ninject;
|
||||||
using Artemis.Core.Plugins.Abstract;
|
using Artemis.Core.Plugins.Abstract;
|
||||||
using Artemis.Core.Plugins.Models;
|
using Artemis.Core.Plugins.Models;
|
||||||
using Artemis.Core.Services.Interfaces;
|
using Artemis.Core.Services.Interfaces;
|
||||||
using Artemis.Core.Services.Storage.Interfaces;
|
using Artemis.Core.Services.Storage.Interfaces;
|
||||||
|
using Artemis.Core.Utilities;
|
||||||
using Artemis.Storage;
|
using Artemis.Storage;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using RGB.NET.Core;
|
using RGB.NET.Core;
|
||||||
@ -35,6 +38,7 @@ namespace Artemis.Core.Services
|
|||||||
private readonly ISurfaceService _surfaceService;
|
private readonly ISurfaceService _surfaceService;
|
||||||
private List<BaseDataModelExpansion> _dataModelExpansions;
|
private List<BaseDataModelExpansion> _dataModelExpansions;
|
||||||
private List<Module> _modules;
|
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
|
// 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,
|
internal CoreService(ILogger logger, StorageMigrationService _, ISettingsService settingsService, IPluginService pluginService,
|
||||||
@ -90,11 +94,38 @@ namespace Artemis.Core.Services
|
|||||||
else
|
else
|
||||||
_logger.Information("Initialized without an active surface entity");
|
_logger.Information("Initialized without an active surface entity");
|
||||||
|
|
||||||
|
PlayIntroAnimation();
|
||||||
_profileService.ActivateLastActiveProfiles();
|
_profileService.ActivateLastActiveProfiles();
|
||||||
|
|
||||||
OnInitialized();
|
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)
|
public void SetMainWindowHandle(IntPtr handle)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core.Events;
|
using Artemis.Core.Events;
|
||||||
|
|
||||||
namespace Artemis.Core.Services.Interfaces
|
namespace Artemis.Core.Services.Interfaces
|
||||||
|
|||||||
@ -1,10 +1,14 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core.Models.Profile;
|
using Artemis.Core.Models.Profile;
|
||||||
using Artemis.Core.Plugins.Abstract;
|
using Artemis.Core.Plugins.Abstract;
|
||||||
using Artemis.Core.Services.Interfaces;
|
using Artemis.Core.Services.Interfaces;
|
||||||
|
|
||||||
namespace Artemis.Core.Services.Storage.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
|
public interface IProfileService : IArtemisService
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <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="module">The profile module to create the profile for</param>
|
||||||
/// <param name="name">The name of the new profile</param>
|
/// <param name="name">The name of the new profile</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
ProfileDescriptor CreateProfile(ProfileModule module, string name);
|
ProfileDescriptor CreateProfileDescriptor(ProfileModule module, string name);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a descriptor for each profile stored for the given <see cref="ProfileModule" />
|
/// Gets a descriptor for each profile stored for the given <see cref="ProfileModule" />
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="module">The module to return profile descriptors for</param>
|
/// <param name="module">The module to return profile descriptors for</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
List<ProfileDescriptor> GetProfiles(ProfileModule module);
|
List<ProfileDescriptor> GetProfileDescriptors(ProfileModule module);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Writes the profile to persistent storage
|
/// Writes the profile to persistent storage
|
||||||
@ -40,30 +44,53 @@ namespace Artemis.Core.Services.Storage.Interfaces
|
|||||||
/// <param name="profile">The profile to delete</param>
|
/// <param name="profile">The profile to delete</param>
|
||||||
void DeleteProfile(Profile profile);
|
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>
|
/// <summary>
|
||||||
/// Activates the profile described in the given <see cref="ProfileDescriptor" /> with the currently active surface
|
/// Activates the profile described in the given <see cref="ProfileDescriptor" /> with the currently active surface
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="profileDescriptor">The descriptor describing the profile to activate</param>
|
/// <param name="profileDescriptor">The descriptor describing the profile to activate</param>
|
||||||
Profile ActivateProfile(ProfileDescriptor profileDescriptor);
|
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>
|
/// <summary>
|
||||||
/// Clears the active profile on the given <see cref="ProfileModule" />
|
/// Clears the active profile on the given <see cref="ProfileModule" />
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="module">The profile module to deactivate the active profile on</param>
|
/// <param name="module">The profile module to deactivate the active profile on</param>
|
||||||
void ClearActiveProfile(ProfileModule module);
|
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>
|
/// <summary>
|
||||||
/// Attempts to restore the profile to the state it had before the last <see cref="UpdateProfile" /> call.
|
/// Attempts to restore the profile to the state it had before the last <see cref="UpdateProfile" /> call.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="selectedProfile"></param>
|
/// <param name="profile"></param>
|
||||||
/// <param name="module"></param>
|
bool UndoUpdateProfile(Profile profile);
|
||||||
bool UndoUpdateProfile(Profile selectedProfile, ProfileModule module);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Attempts to restore the profile to the state it had before the last <see cref="UndoUpdateProfile" /> call.
|
/// Attempts to restore the profile to the state it had before the last <see cref="UndoUpdateProfile" /> call.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="selectedProfile"></param>
|
/// <param name="profile"></param>
|
||||||
/// <param name="module"></param>
|
bool RedoUpdateProfile(Profile profile);
|
||||||
bool RedoUpdateProfile(Profile selectedProfile, ProfileModule module);
|
|
||||||
|
/// <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;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core.Events;
|
using Artemis.Core.Events;
|
||||||
using Artemis.Core.Models.Profile;
|
using Artemis.Core.Models.Profile;
|
||||||
using Artemis.Core.Models.Surface;
|
using Artemis.Core.Models.Surface;
|
||||||
@ -15,9 +16,6 @@ using Serilog;
|
|||||||
|
|
||||||
namespace Artemis.Core.Services.Storage
|
namespace Artemis.Core.Services.Storage
|
||||||
{
|
{
|
||||||
/// <summary>
|
|
||||||
/// Provides access to profile storage and is responsible for activating default profiles
|
|
||||||
/// </summary>
|
|
||||||
public class ProfileService : IProfileService
|
public class ProfileService : IProfileService
|
||||||
{
|
{
|
||||||
private readonly ILogger _logger;
|
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);
|
var profileEntities = _profileRepository.GetByPluginGuid(module.PluginInfo.Guid);
|
||||||
return profileEntities.Select(e => new ProfileDescriptor(module, e)).ToList();
|
return profileEntities.Select(e => new ProfileDescriptor(module, e)).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProfileDescriptor GetLastActiveProfile(ProfileModule module)
|
public ProfileDescriptor CreateProfileDescriptor(ProfileModule module, string name)
|
||||||
{
|
|
||||||
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)
|
|
||||||
{
|
{
|
||||||
var profileEntity = new ProfileEntity {Id = Guid.NewGuid(), Name = name, PluginGuid = module.PluginInfo.Guid};
|
var profileEntity = new ProfileEntity {Id = Guid.NewGuid(), Name = name, PluginGuid = module.PluginInfo.Guid};
|
||||||
return new ProfileDescriptor(module, profileEntity);
|
return new ProfileDescriptor(module, profileEntity);
|
||||||
@ -72,31 +63,59 @@ namespace Artemis.Core.Services.Storage
|
|||||||
|
|
||||||
public Profile ActivateProfile(ProfileDescriptor profileDescriptor)
|
public Profile ActivateProfile(ProfileDescriptor profileDescriptor)
|
||||||
{
|
{
|
||||||
if (profileDescriptor.ProfileModule.ActiveProfile.EntityId == profileDescriptor.Id)
|
if (profileDescriptor.ProfileModule.ActiveProfile?.EntityId == profileDescriptor.Id)
|
||||||
return profileDescriptor.ProfileModule.ActiveProfile;
|
return profileDescriptor.ProfileModule.ActiveProfile;
|
||||||
|
|
||||||
var profile = new Profile(profileDescriptor.ProfileModule, profileDescriptor.ProfileEntity);
|
var profileEntity = _profileRepository.Get(profileDescriptor.Id);
|
||||||
InitializeLayerProperties(profile);
|
var profile = new Profile(profileDescriptor.ProfileModule, profileEntity);
|
||||||
InstantiateLayers(profile);
|
InstantiateProfile(profile);
|
||||||
InstantiateFolders(profile);
|
|
||||||
|
|
||||||
profileDescriptor.ProfileModule.ChangeActiveProfile(profile, _surfaceService.ActiveSurface);
|
profileDescriptor.ProfileModule.ChangeActiveProfile(profile, _surfaceService.ActiveSurface);
|
||||||
return profile;
|
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)
|
public void ClearActiveProfile(ProfileModule module)
|
||||||
{
|
{
|
||||||
module.ChangeActiveProfile(null, _surfaceService.ActiveSurface);
|
module.ChangeActiveProfile(null, _surfaceService.ActiveSurface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task ClearActiveProfileAnimated(ProfileModule module)
|
||||||
|
{
|
||||||
|
await module.ChangeActiveProfileAnimated(null, _surfaceService.ActiveSurface);
|
||||||
|
}
|
||||||
|
|
||||||
public void DeleteProfile(Profile profile)
|
public void DeleteProfile(Profile profile)
|
||||||
{
|
{
|
||||||
_logger.Debug("Removing 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);
|
_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)
|
public void UpdateProfile(Profile profile, bool includeChildren)
|
||||||
{
|
{
|
||||||
_logger.Debug("Updating profile " + profile);
|
_logger.Debug("Updating profile " + profile);
|
||||||
@ -116,46 +135,73 @@ namespace Artemis.Core.Services.Storage
|
|||||||
_profileRepository.Save(profile.ProfileEntity);
|
_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");
|
if (!profile.UndoStack.Any())
|
||||||
return false;
|
{
|
||||||
}
|
_logger.Debug("Undo profile update - Failed, undo stack empty");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ActivateProfile(module, null);
|
var top = profile.UndoStack.Pop();
|
||||||
var top = profile.UndoStack.Pop();
|
var memento = JsonConvert.SerializeObject(profile.ProfileEntity, MementoSettings);
|
||||||
var memento = JsonConvert.SerializeObject(profile.ProfileEntity, MementoSettings);
|
profile.RedoStack.Push(memento);
|
||||||
profile.RedoStack.Push(memento);
|
profile.ProfileEntity = JsonConvert.DeserializeObject<ProfileEntity>(top, MementoSettings);
|
||||||
profile.ProfileEntity = JsonConvert.DeserializeObject<ProfileEntity>(top, MementoSettings);
|
|
||||||
profile.ApplyToProfile();
|
profile.ApplyToProfile();
|
||||||
ActivateProfile(module, profile);
|
InstantiateProfile(profile);
|
||||||
|
}
|
||||||
|
|
||||||
_logger.Debug("Undo profile update - Success");
|
_logger.Debug("Undo profile update - Success");
|
||||||
return true;
|
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");
|
if (!profile.RedoStack.Any())
|
||||||
return false;
|
{
|
||||||
|
_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)
|
private void InitializeLayerProperties(Profile profile)
|
||||||
{
|
{
|
||||||
foreach (var layer in profile.GetAllLayers())
|
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)
|
private void InstantiateFolders(Profile profile)
|
||||||
{
|
{
|
||||||
foreach (var folder in profile.GetAllFolders())
|
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)
|
private void InstantiateLayers(Profile profile)
|
||||||
{
|
{
|
||||||
foreach (var layer in profile.GetAllLayers())
|
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)
|
private void ActiveProfilesPopulateLeds(ArtemisSurface surface)
|
||||||
{
|
{
|
||||||
var profileModules = _pluginService.GetPluginsOfType<ProfileModule>();
|
var profileModules = _pluginService.GetPluginsOfType<ProfileModule>();
|
||||||
@ -211,6 +267,10 @@ namespace Artemis.Core.Services.Storage
|
|||||||
profileModule.ActiveProfile.PopulateLeds(surface);
|
profileModule.ActiveProfile.PopulateLeds(surface);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Instantiates all missing plugin-related classes on the profile trees of all currently active profiles
|
||||||
|
/// </summary>
|
||||||
private void ActiveProfilesInstantiatePlugins()
|
private void ActiveProfilesInstantiatePlugins()
|
||||||
{
|
{
|
||||||
var profileModules = _pluginService.GetPluginsOfType<ProfileModule>();
|
var profileModules = _pluginService.GetPluginsOfType<ProfileModule>();
|
||||||
@ -242,8 +302,8 @@ namespace Artemis.Core.Services.Storage
|
|||||||
ActiveProfilesInstantiatePlugins();
|
ActiveProfilesInstantiatePlugins();
|
||||||
else if (e.PluginInfo.Instance is ProfileModule profileModule)
|
else if (e.PluginInfo.Instance is ProfileModule profileModule)
|
||||||
{
|
{
|
||||||
var activeProfile = GetActiveProfile(profileModule);
|
var activeProfile = GetLastActiveProfile(profileModule);
|
||||||
ActivateProfile(profileModule, activeProfile);
|
ActivateProfile(activeProfile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
92
src/Artemis.Core/Utilities/IntroAnimation.cs
Normal file
92
src/Artemis.Core/Utilities/IntroAnimation.cs
Normal file
@ -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>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -24,9 +24,9 @@ namespace Artemis.UI.Shared.Services.Interfaces
|
|||||||
void ChangeSelectedProfileElement(RenderProfileElement profileElement);
|
void ChangeSelectedProfileElement(RenderProfileElement profileElement);
|
||||||
void UpdateSelectedProfileElement();
|
void UpdateSelectedProfileElement();
|
||||||
void UpdateProfilePreview();
|
void UpdateProfilePreview();
|
||||||
bool UndoUpdateProfile(ProfileModule module);
|
bool UndoUpdateProfile();
|
||||||
bool RedoUpdateProfile(ProfileModule module);
|
bool RedoUpdateProfile();
|
||||||
Module GetCurrentModule();
|
ProfileModule GetCurrentModule();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs when a new profile is selected
|
/// Occurs when a new profile is selected
|
||||||
|
|||||||
@ -77,8 +77,9 @@ namespace Artemis.UI.Shared.Services
|
|||||||
|
|
||||||
var profileElementEvent = new ProfileEventArgs(profile, SelectedProfile);
|
var profileElementEvent = new ProfileEventArgs(profile, SelectedProfile);
|
||||||
SelectedProfile = profile;
|
SelectedProfile = profile;
|
||||||
UpdateProfilePreview();
|
|
||||||
OnSelectedProfileChanged(profileElementEvent);
|
OnSelectedProfileChanged(profileElementEvent);
|
||||||
|
UpdateProfilePreview();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,8 +89,9 @@ namespace Artemis.UI.Shared.Services
|
|||||||
{
|
{
|
||||||
_logger.Verbose("UpdateSelectedProfile {profile}", SelectedProfile);
|
_logger.Verbose("UpdateSelectedProfile {profile}", SelectedProfile);
|
||||||
_profileService.UpdateProfile(SelectedProfile, true);
|
_profileService.UpdateProfile(SelectedProfile, true);
|
||||||
UpdateProfilePreview();
|
|
||||||
OnSelectedProfileChanged(new ProfileEventArgs(SelectedProfile));
|
OnSelectedProfileChanged(new ProfileEventArgs(SelectedProfile));
|
||||||
|
UpdateProfilePreview();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,13 +134,19 @@ namespace Artemis.UI.Shared.Services
|
|||||||
OnProfilePreviewUpdated();
|
OnProfilePreviewUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool UndoUpdateProfile(ProfileModule module)
|
public bool UndoUpdateProfile()
|
||||||
{
|
{
|
||||||
var undid = _profileService.UndoUpdateProfile(SelectedProfile, module);
|
var undid = _profileService.UndoUpdateProfile(SelectedProfile);
|
||||||
if (!undid)
|
if (!undid)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
|
if (SelectedProfileElement is Folder folder)
|
||||||
|
SelectedProfileElement = SelectedProfile.GetAllFolders().FirstOrDefault(f => f.EntityId == folder.EntityId);
|
||||||
|
else if (SelectedProfileElement is Layer layer)
|
||||||
|
SelectedProfileElement = SelectedProfile.GetAllLayers().FirstOrDefault(l => l.EntityId == layer.EntityId);
|
||||||
|
|
||||||
OnSelectedProfileChanged(new ProfileEventArgs(SelectedProfile, SelectedProfile));
|
OnSelectedProfileChanged(new ProfileEventArgs(SelectedProfile, SelectedProfile));
|
||||||
|
OnSelectedProfileElementChanged(new RenderProfileElementEventArgs(SelectedProfileElement));
|
||||||
|
|
||||||
if (SelectedProfileElement != null)
|
if (SelectedProfileElement != null)
|
||||||
{
|
{
|
||||||
@ -152,9 +160,9 @@ namespace Artemis.UI.Shared.Services
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool RedoUpdateProfile(ProfileModule module)
|
public bool RedoUpdateProfile()
|
||||||
{
|
{
|
||||||
var redid = _profileService.RedoUpdateProfile(SelectedProfile, module);
|
var redid = _profileService.RedoUpdateProfile(SelectedProfile);
|
||||||
if (!redid)
|
if (!redid)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -248,9 +256,9 @@ namespace Artemis.UI.Shared.Services
|
|||||||
return time;
|
return time;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Module GetCurrentModule()
|
public ProfileModule GetCurrentModule()
|
||||||
{
|
{
|
||||||
return (Module) SelectedProfile?.PluginInfo.Instance;
|
return SelectedProfile?.Module;
|
||||||
}
|
}
|
||||||
|
|
||||||
public event EventHandler<ProfileEventArgs> ProfileSelected;
|
public event EventHandler<ProfileEventArgs> ProfileSelected;
|
||||||
|
|||||||
@ -79,7 +79,7 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<RadioButton Grid.Column="0"
|
<RadioButton Grid.Column="0"
|
||||||
Style="{StaticResource MaterialDesignTabRadioButton}"
|
Style="{StaticResource MaterialDesignTabRadioButton}"
|
||||||
IsChecked="{Binding RenderProfileElement.DisplayContinuously}"
|
IsChecked="{Binding DisplayContinuously}"
|
||||||
MinWidth="0"
|
MinWidth="0"
|
||||||
Padding="5 0">
|
Padding="5 0">
|
||||||
<RadioButton.ToolTip>
|
<RadioButton.ToolTip>
|
||||||
@ -96,7 +96,7 @@
|
|||||||
</RadioButton>
|
</RadioButton>
|
||||||
<RadioButton Grid.Column="1"
|
<RadioButton Grid.Column="1"
|
||||||
Style="{StaticResource MaterialDesignTabRadioButton}"
|
Style="{StaticResource MaterialDesignTabRadioButton}"
|
||||||
IsChecked="{Binding RenderProfileElement.DisplayContinuously, Converter={StaticResource InverseBooleanConverter}}"
|
IsChecked="{Binding DisplayContinuously, Converter={StaticResource InverseBooleanConverter}}"
|
||||||
MinWidth="0"
|
MinWidth="0"
|
||||||
Padding="5 0">
|
Padding="5 0">
|
||||||
<RadioButton.ToolTip>
|
<RadioButton.ToolTip>
|
||||||
@ -135,7 +135,7 @@
|
|||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<RadioButton Grid.Column="0"
|
<RadioButton Grid.Column="0"
|
||||||
Style="{StaticResource MaterialDesignTabRadioButton}"
|
Style="{StaticResource MaterialDesignTabRadioButton}"
|
||||||
IsChecked="{Binding RenderProfileElement.AlwaysFinishTimeline}"
|
IsChecked="{Binding AlwaysFinishTimeline}"
|
||||||
MinWidth="0"
|
MinWidth="0"
|
||||||
Padding="5 0">
|
Padding="5 0">
|
||||||
<RadioButton.ToolTip>
|
<RadioButton.ToolTip>
|
||||||
@ -152,7 +152,7 @@
|
|||||||
</RadioButton>
|
</RadioButton>
|
||||||
<RadioButton Grid.Column="1"
|
<RadioButton Grid.Column="1"
|
||||||
Style="{StaticResource MaterialDesignTabRadioButton}"
|
Style="{StaticResource MaterialDesignTabRadioButton}"
|
||||||
IsChecked="{Binding RenderProfileElement.AlwaysFinishTimeline, Converter={StaticResource InverseBooleanConverter}}"
|
IsChecked="{Binding AlwaysFinishTimeline, Converter={StaticResource InverseBooleanConverter}}"
|
||||||
MinWidth="0"
|
MinWidth="0"
|
||||||
Padding="5 0">
|
Padding="5 0">
|
||||||
<RadioButton.ToolTip>
|
<RadioButton.ToolTip>
|
||||||
|
|||||||
@ -14,6 +14,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
private RenderProfileElement _renderProfileElement;
|
private RenderProfileElement _renderProfileElement;
|
||||||
private DisplayConditionGroupViewModel _rootGroup;
|
private DisplayConditionGroupViewModel _rootGroup;
|
||||||
private int _transitionerIndex;
|
private int _transitionerIndex;
|
||||||
|
private bool _displayContinuously;
|
||||||
|
private bool _alwaysFinishTimeline;
|
||||||
|
|
||||||
public DisplayConditionsViewModel(IProfileEditorService profileEditorService, IDisplayConditionsVmFactory displayConditionsVmFactory)
|
public DisplayConditionsViewModel(IProfileEditorService profileEditorService, IDisplayConditionsVmFactory displayConditionsVmFactory)
|
||||||
{
|
{
|
||||||
@ -39,15 +41,22 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
set => SetAndNotify(ref _renderProfileElement, value);
|
set => SetAndNotify(ref _renderProfileElement, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int ConditionBehaviourIndex
|
public bool DisplayContinuously
|
||||||
{
|
{
|
||||||
get => RenderProfileElement != null && RenderProfileElement.AlwaysFinishTimeline ? 0 : 1;
|
get => _displayContinuously;
|
||||||
set
|
set
|
||||||
{
|
{
|
||||||
if (RenderProfileElement == null)
|
if (!SetAndNotify(ref _displayContinuously, value)) return;
|
||||||
return;
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
RenderProfileElement.AlwaysFinishTimeline = value == 0;
|
public bool AlwaysFinishTimeline
|
||||||
|
{
|
||||||
|
get => _alwaysFinishTimeline;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!SetAndNotify(ref _alwaysFinishTimeline, value)) return;
|
||||||
_profileEditorService.UpdateSelectedProfileElement();
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -70,9 +79,13 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
private void ProfileEditorServiceOnProfileElementSelected(object sender, RenderProfileElementEventArgs e)
|
private void ProfileEditorServiceOnProfileElementSelected(object sender, RenderProfileElementEventArgs e)
|
||||||
{
|
{
|
||||||
RenderProfileElement = e.RenderProfileElement;
|
RenderProfileElement = e.RenderProfileElement;
|
||||||
NotifyOfPropertyChange(nameof(ConditionBehaviourIndex));
|
|
||||||
NotifyOfPropertyChange(nameof(ConditionBehaviourEnabled));
|
NotifyOfPropertyChange(nameof(ConditionBehaviourEnabled));
|
||||||
|
|
||||||
|
_displayContinuously = RenderProfileElement?.DisplayContinuously ?? false;
|
||||||
|
NotifyOfPropertyChange(nameof(DisplayContinuously));
|
||||||
|
_alwaysFinishTimeline = RenderProfileElement?.AlwaysFinishTimeline ?? false;
|
||||||
|
NotifyOfPropertyChange(nameof(AlwaysFinishTimeline));
|
||||||
|
|
||||||
if (e.RenderProfileElement == null)
|
if (e.RenderProfileElement == null)
|
||||||
{
|
{
|
||||||
RootGroup?.Dispose();
|
RootGroup?.Dispose();
|
||||||
|
|||||||
@ -209,7 +209,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
|||||||
public List<LayerPropertyGroupViewModel> GetAllLayerPropertyGroupViewModels()
|
public List<LayerPropertyGroupViewModel> GetAllLayerPropertyGroupViewModels()
|
||||||
{
|
{
|
||||||
var groups = LayerPropertyGroups.ToList();
|
var groups = LayerPropertyGroups.ToList();
|
||||||
groups.AddRange(groups.SelectMany(g => g.Children).Where(g => g is LayerPropertyGroupViewModel).Cast<LayerPropertyGroupViewModel>());
|
var toAdd = groups.SelectMany(g => g.Children).Where(g => g is LayerPropertyGroupViewModel).Cast<LayerPropertyGroupViewModel>().ToList();
|
||||||
|
groups.AddRange(toAdd);
|
||||||
return groups;
|
return groups;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -9,6 +9,7 @@ using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Abstract;
|
|||||||
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline;
|
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline;
|
||||||
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Tree;
|
using Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Tree;
|
||||||
using Artemis.UI.Shared.Services.Interfaces;
|
using Artemis.UI.Shared.Services.Interfaces;
|
||||||
|
using Humanizer;
|
||||||
using Ninject;
|
using Ninject;
|
||||||
using Ninject.Parameters;
|
using Ninject.Parameters;
|
||||||
|
|
||||||
@ -42,6 +43,16 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
|||||||
TreePropertyGroupViewModel = _layerPropertyVmFactory.TreePropertyGroupViewModel(this);
|
TreePropertyGroupViewModel = _layerPropertyVmFactory.TreePropertyGroupViewModel(this);
|
||||||
TimelinePropertyGroupViewModel = _layerPropertyVmFactory.TimelinePropertyGroupViewModel(this);
|
TimelinePropertyGroupViewModel = _layerPropertyVmFactory.TimelinePropertyGroupViewModel(this);
|
||||||
|
|
||||||
|
// Generate a fallback name if the description does not contain one
|
||||||
|
if (PropertyGroupDescription.Name == null)
|
||||||
|
{
|
||||||
|
var propertyInfo = LayerPropertyGroup.Parent?.GetType().GetProperties().FirstOrDefault(p => ReferenceEquals(p.GetValue(LayerPropertyGroup.Parent), LayerPropertyGroup));
|
||||||
|
if (propertyInfo != null)
|
||||||
|
PropertyGroupDescription.Name = propertyInfo.Name.Humanize();
|
||||||
|
else
|
||||||
|
PropertyGroupDescription.Name = "Unknown group";
|
||||||
|
}
|
||||||
|
|
||||||
LayerPropertyGroup.VisibilityChanged += LayerPropertyGroupOnVisibilityChanged;
|
LayerPropertyGroup.VisibilityChanged += LayerPropertyGroupOnVisibilityChanged;
|
||||||
PopulateChildren();
|
PopulateChildren();
|
||||||
DetermineType();
|
DetermineType();
|
||||||
|
|||||||
@ -21,7 +21,8 @@
|
|||||||
Text="{Binding LayerPropertyGroupViewModel.PropertyGroupDescription.Name}"
|
Text="{Binding LayerPropertyGroupViewModel.PropertyGroupDescription.Name}"
|
||||||
ToolTip="{Binding LayerPropertyGroupViewModel.PropertyGroupDescription.Description}"
|
ToolTip="{Binding LayerPropertyGroupViewModel.PropertyGroupDescription.Description}"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Margin="0 5">
|
HorizontalAlignment="Left"
|
||||||
|
Margin="3 5 0 5">
|
||||||
<TextBlock.Style>
|
<TextBlock.Style>
|
||||||
<Style TargetType="{x:Type TextBlock}">
|
<Style TargetType="{x:Type TextBlock}">
|
||||||
<Setter Property="Visibility" Value="Collapsed" />
|
<Setter Property="Visibility" Value="Collapsed" />
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800"
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
d:DataContext="{d:DesignInstance {x:Type local:TreePropertyViewModel}}">
|
d:DataContext="{d:DesignInstance {x:Type local:TreePropertyViewModel}}">
|
||||||
<Grid Height="22">
|
<Grid Height="22" Margin="-20 0 0 0">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
|
|||||||
@ -7,6 +7,8 @@
|
|||||||
xmlns:s="https://github.com/canton7/Stylet"
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
xmlns:profileEditor="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor"
|
xmlns:profileEditor="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor"
|
||||||
xmlns:behaviors="clr-namespace:Artemis.UI.Behaviors"
|
xmlns:behaviors="clr-namespace:Artemis.UI.Behaviors"
|
||||||
|
xmlns:profile="clr-namespace:Artemis.Core.Models.Profile;assembly=Artemis.Core"
|
||||||
|
xmlns:layerBrush="clr-namespace:Artemis.Core.Plugins.LayerBrush;assembly=Artemis.Core"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
behaviors:InputBindingBehavior.PropagateInputBindingsToWindow="True"
|
behaviors:InputBindingBehavior.PropagateInputBindingsToWindow="True"
|
||||||
d:DesignHeight="450" d:DesignWidth="800"
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
@ -19,6 +21,38 @@
|
|||||||
<ResourceDictionary
|
<ResourceDictionary
|
||||||
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.PopupBox.xaml" />
|
Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.PopupBox.xaml" />
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
|
||||||
|
<ControlTemplate x:Key="SimpleTemplate">
|
||||||
|
<StackPanel d:DataContext="{d:DesignInstance {x:Type profile:ProfileDescriptor}}" Orientation="Horizontal">
|
||||||
|
<TextBlock Text="{Binding Name}" />
|
||||||
|
</StackPanel>
|
||||||
|
</ControlTemplate>
|
||||||
|
<ControlTemplate x:Key="ExtendedTemplate">
|
||||||
|
<Grid d:DataContext="{d:DesignInstance {x:Type profile:ProfileDescriptor}}">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
|
<ColumnDefinition Width="Auto" />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<TextBlock Text="{Binding Name}" VerticalAlignment="Center" />
|
||||||
|
<Button Grid.Column="1"
|
||||||
|
Style="{StaticResource MaterialDesignFloatingActionMiniDarkButton}"
|
||||||
|
Width="26"
|
||||||
|
Height="26"
|
||||||
|
VerticalAlignment="Top"
|
||||||
|
Command="{s:Action DeleteProfile}"
|
||||||
|
CommandParameter="{Binding}">
|
||||||
|
<materialDesign:PackIcon Kind="TrashCanOutline" Height="14" Width="14" HorizontalAlignment="Right" />
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
</ControlTemplate>
|
||||||
|
<DataTemplate x:Key="ProfileDescriptorTemplate">
|
||||||
|
<Control x:Name="TemplateControl" Focusable="False" Template="{StaticResource ExtendedTemplate}" />
|
||||||
|
<DataTemplate.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType={x:Type ComboBoxItem}}, Path=IsSelected}" Value="{x:Null}">
|
||||||
|
<Setter TargetName="TemplateControl" Property="Template" Value="{StaticResource SimpleTemplate}" />
|
||||||
|
</DataTrigger>
|
||||||
|
</DataTemplate.Triggers>
|
||||||
|
</DataTemplate>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
|
|
||||||
@ -98,12 +132,11 @@
|
|||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
<ComboBox Name="LocaleCombo"
|
<ComboBox Height="26"
|
||||||
Height="26"
|
|
||||||
VerticalAlignment="Top"
|
VerticalAlignment="Top"
|
||||||
ItemsSource="{Binding Profiles}"
|
ItemsSource="{Binding Profiles}"
|
||||||
SelectedItem="{Binding SelectedProfile}"
|
SelectedItem="{Binding SelectedProfile}"
|
||||||
DisplayMemberPath="Name">
|
ItemTemplate="{StaticResource ProfileDescriptorTemplate}">
|
||||||
<ComboBox.ItemsPanel>
|
<ComboBox.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
<VirtualizingStackPanel />
|
<VirtualizingStackPanel />
|
||||||
|
|||||||
@ -25,7 +25,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
|
|||||||
private readonly IProfileService _profileService;
|
private readonly IProfileService _profileService;
|
||||||
private readonly ISettingsService _settingsService;
|
private readonly ISettingsService _settingsService;
|
||||||
private readonly ISnackbarMessageQueue _snackbarMessageQueue;
|
private readonly ISnackbarMessageQueue _snackbarMessageQueue;
|
||||||
private BindableCollection<Profile> _profiles;
|
private BindableCollection<ProfileDescriptor> _profiles;
|
||||||
private PluginSetting<GridLength> _sidePanelsWidth;
|
private PluginSetting<GridLength> _sidePanelsWidth;
|
||||||
private PluginSetting<GridLength> _displayConditionsHeight;
|
private PluginSetting<GridLength> _displayConditionsHeight;
|
||||||
private PluginSetting<GridLength> _bottomPanelsHeight;
|
private PluginSetting<GridLength> _bottomPanelsHeight;
|
||||||
@ -34,6 +34,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
|
|||||||
private ProfileTreeViewModel _profileTreeViewModel;
|
private ProfileTreeViewModel _profileTreeViewModel;
|
||||||
private LayerPropertiesViewModel _layerPropertiesViewModel;
|
private LayerPropertiesViewModel _layerPropertiesViewModel;
|
||||||
private DisplayConditionsViewModel _displayConditionsViewModel;
|
private DisplayConditionsViewModel _displayConditionsViewModel;
|
||||||
|
private ProfileDescriptor _selectedProfile;
|
||||||
|
|
||||||
public ProfileEditorViewModel(ProfileModule module,
|
public ProfileEditorViewModel(ProfileModule module,
|
||||||
ICollection<ProfileEditorPanelViewModel> viewModels,
|
ICollection<ProfileEditorPanelViewModel> viewModels,
|
||||||
@ -52,7 +53,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
|
|||||||
Module = module;
|
Module = module;
|
||||||
DialogService = dialogService;
|
DialogService = dialogService;
|
||||||
|
|
||||||
Profiles = new BindableCollection<Profile>();
|
Profiles = new BindableCollection<ProfileDescriptor>();
|
||||||
|
|
||||||
// Run this first to let VMs activate without causing constant UI updates
|
// Run this first to let VMs activate without causing constant UI updates
|
||||||
Items.AddRange(viewModels);
|
Items.AddRange(viewModels);
|
||||||
@ -91,7 +92,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
|
|||||||
set => SetAndNotify(ref _profileViewModel, value);
|
set => SetAndNotify(ref _profileViewModel, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public BindableCollection<Profile> Profiles
|
public BindableCollection<ProfileDescriptor> Profiles
|
||||||
{
|
{
|
||||||
get => _profiles;
|
get => _profiles;
|
||||||
set => SetAndNotify(ref _profiles, value);
|
set => SetAndNotify(ref _profiles, value);
|
||||||
@ -121,17 +122,22 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
|
|||||||
set => SetAndNotify(ref _elementPropertiesWidth, value);
|
set => SetAndNotify(ref _elementPropertiesWidth, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Profile SelectedProfile
|
public ProfileDescriptor SelectedProfile
|
||||||
{
|
{
|
||||||
get => Module.ActiveProfile;
|
get => _selectedProfile;
|
||||||
set => ChangeSelectedProfile(value);
|
set
|
||||||
|
{
|
||||||
|
if (!SetAndNotify(ref _selectedProfile, value)) return;
|
||||||
|
NotifyOfPropertyChange(nameof(CanDeleteActiveProfile));
|
||||||
|
ActivateSelectedProfile();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanDeleteActiveProfile => SelectedProfile != null && Profiles.Count > 1;
|
public bool CanDeleteActiveProfile => SelectedProfile != null && Profiles.Count > 1;
|
||||||
|
|
||||||
public Profile CreateProfile(string name)
|
public ProfileDescriptor CreateProfile(string name)
|
||||||
{
|
{
|
||||||
var profile = _profileService.CreateProfile(Module, name);
|
var profile = _profileService.CreateProfileDescriptor(Module, name);
|
||||||
Profiles.Add(profile);
|
Profiles.Add(profile);
|
||||||
return profile;
|
return profile;
|
||||||
}
|
}
|
||||||
@ -146,6 +152,17 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async Task DeleteProfile(ProfileDescriptor profileDescriptor)
|
||||||
|
{
|
||||||
|
var result = await DialogService.ShowConfirmDialog(
|
||||||
|
"Delete profile",
|
||||||
|
$"Are you sure you want to delete '{profileDescriptor.Name}'? This cannot be undone."
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result)
|
||||||
|
RemoveProfile(profileDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
public async Task DeleteActiveProfile()
|
public async Task DeleteActiveProfile()
|
||||||
{
|
{
|
||||||
var result = await DialogService.ShowConfirmDialog(
|
var result = await DialogService.ShowConfirmDialog(
|
||||||
@ -153,21 +170,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
|
|||||||
"Are you sure you want to delete your currently active profile? This cannot be undone."
|
"Are you sure you want to delete your currently active profile? This cannot be undone."
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!result || !CanDeleteActiveProfile)
|
if (result)
|
||||||
return;
|
RemoveProfile(SelectedProfile);
|
||||||
|
|
||||||
var profile = SelectedProfile;
|
|
||||||
var index = Profiles.IndexOf(profile);
|
|
||||||
|
|
||||||
// Get a new active profile
|
|
||||||
var newActiveProfile = index - 1 > -1 ? Profiles[index - 1] : Profiles[index + 1];
|
|
||||||
|
|
||||||
// Activate the new active profile
|
|
||||||
SelectedProfile = newActiveProfile;
|
|
||||||
|
|
||||||
// Remove the old one
|
|
||||||
Profiles.Remove(profile);
|
|
||||||
_profileService.DeleteProfile(profile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Undo()
|
public void Undo()
|
||||||
@ -176,7 +180,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
|
|||||||
var beforeGroups = LayerPropertiesViewModel.GetAllLayerPropertyGroupViewModels();
|
var beforeGroups = LayerPropertiesViewModel.GetAllLayerPropertyGroupViewModels();
|
||||||
var expandedPaths = beforeGroups.Where(g => g.IsExpanded).Select(g => g.LayerPropertyGroup.Path).ToList();
|
var expandedPaths = beforeGroups.Where(g => g.IsExpanded).Select(g => g.LayerPropertyGroup.Path).ToList();
|
||||||
|
|
||||||
if (!_profileEditorService.UndoUpdateProfile(Module))
|
if (!_profileEditorService.UndoUpdateProfile())
|
||||||
{
|
{
|
||||||
_snackbarMessageQueue.Enqueue("Nothing to undo");
|
_snackbarMessageQueue.Enqueue("Nothing to undo");
|
||||||
return;
|
return;
|
||||||
@ -195,7 +199,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
|
|||||||
var beforeGroups = LayerPropertiesViewModel.GetAllLayerPropertyGroupViewModels();
|
var beforeGroups = LayerPropertiesViewModel.GetAllLayerPropertyGroupViewModels();
|
||||||
var expandedPaths = beforeGroups.Where(g => g.IsExpanded).Select(g => g.LayerPropertyGroup.Path).ToList();
|
var expandedPaths = beforeGroups.Where(g => g.IsExpanded).Select(g => g.LayerPropertyGroup.Path).ToList();
|
||||||
|
|
||||||
if (!_profileEditorService.RedoUpdateProfile(Module))
|
if (!_profileEditorService.RedoUpdateProfile())
|
||||||
{
|
{
|
||||||
_snackbarMessageQueue.Enqueue("Nothing to redo");
|
_snackbarMessageQueue.Enqueue("Nothing to redo");
|
||||||
return;
|
return;
|
||||||
@ -225,29 +229,38 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
|
|||||||
base.OnClose();
|
base.OnClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ChangeSelectedProfile(Profile profile)
|
private void RemoveProfile(ProfileDescriptor profileDescriptor)
|
||||||
{
|
{
|
||||||
var oldProfile = Module.ActiveProfile;
|
if (SelectedProfile == profileDescriptor && !CanDeleteActiveProfile)
|
||||||
_profileService.ActivateProfile(Module, profile);
|
return;
|
||||||
|
|
||||||
if (oldProfile != null)
|
var index = Profiles.IndexOf(profileDescriptor);
|
||||||
_profileService.UpdateProfile(oldProfile, false);
|
|
||||||
if (profile != null)
|
|
||||||
_profileService.UpdateProfile(profile, false);
|
|
||||||
|
|
||||||
if (_profileEditorService.SelectedProfile != profile)
|
// Get a new active profile
|
||||||
|
var newActiveProfile = index - 1 > -1 ? Profiles[index - 1] : Profiles[index + 1];
|
||||||
|
|
||||||
|
// Activate the new active profile
|
||||||
|
SelectedProfile = newActiveProfile;
|
||||||
|
|
||||||
|
// Remove the old one
|
||||||
|
Profiles.Remove(profileDescriptor);
|
||||||
|
_profileService.DeleteProfile(profileDescriptor);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ActivateSelectedProfile()
|
||||||
|
{
|
||||||
|
Execute.PostToUIThread(async () =>
|
||||||
|
{
|
||||||
|
var changeTask = _profileService.ActivateProfileAnimated(SelectedProfile);
|
||||||
|
_profileEditorService.ChangeSelectedProfile(null);
|
||||||
|
var profile = await changeTask;
|
||||||
_profileEditorService.ChangeSelectedProfile(profile);
|
_profileEditorService.ChangeSelectedProfile(profile);
|
||||||
|
});
|
||||||
NotifyOfPropertyChange(nameof(SelectedProfile));
|
|
||||||
NotifyOfPropertyChange(nameof(CanDeleteActiveProfile));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ModuleOnActiveProfileChanged(object sender, EventArgs e)
|
private void ModuleOnActiveProfileChanged(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
if (SelectedProfile == Module.ActiveProfile)
|
SelectedProfile = Profiles.FirstOrDefault(d => d.Id == Module.ActiveProfile.EntityId);
|
||||||
return;
|
|
||||||
|
|
||||||
SelectedProfile = Profiles.FirstOrDefault(p => p == Module.ActiveProfile);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void LoadWorkspaceSettings()
|
private void LoadWorkspaceSettings()
|
||||||
@ -269,29 +282,19 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
|
|||||||
private void LoadProfiles()
|
private void LoadProfiles()
|
||||||
{
|
{
|
||||||
// Get all profiles from the database
|
// Get all profiles from the database
|
||||||
var profiles = _profileService.GetProfiles(Module);
|
Profiles.Clear();
|
||||||
// Get the latest active profile, this falls back to just any profile so if null, create a default profile
|
Profiles.AddRange(_profileService.GetProfileDescriptors(Module).OrderBy(d => d.Name));
|
||||||
var activeProfile = _profileService.GetActiveProfile(Module) ?? _profileService.CreateProfile(Module, "Default");
|
|
||||||
|
|
||||||
// GetActiveProfile can return a duplicate because inactive profiles aren't kept in memory, make sure it's unique in the profiles list
|
// Populate the selected profile
|
||||||
profiles = profiles.Where(p => p.EntityId != activeProfile.EntityId).ToList();
|
SelectedProfile = Profiles.FirstOrDefault(p => p.IsLastActiveProfile);
|
||||||
profiles.Add(activeProfile);
|
|
||||||
|
|
||||||
// Populate the UI collection
|
if (SelectedProfile != null)
|
||||||
Profiles.AddRange(profiles.Except(Profiles).ToList());
|
return;
|
||||||
Profiles.RemoveRange(Profiles.Except(profiles).ToList());
|
|
||||||
var index = 0;
|
|
||||||
foreach (var profile in Profiles.OrderBy(p => p.Name).ToList())
|
|
||||||
{
|
|
||||||
Profiles.Move(Profiles.IndexOf(profile), index);
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
SelectedProfile = activeProfile;
|
// Create a default profile if there is none
|
||||||
if (_profileEditorService.SelectedProfile != activeProfile)
|
var defaultProfile = _profileService.CreateProfileDescriptor(Module, "Default");
|
||||||
_profileEditorService.ChangeSelectedProfile(activeProfile);
|
Profiles.Add(defaultProfile);
|
||||||
if (!activeProfile.IsActivated)
|
SelectedProfile = defaultProfile;
|
||||||
_profileService.ActivateProfile(Module, activeProfile);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -2,9 +2,7 @@
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
using Artemis.Core.Models.Profile;
|
using Artemis.Core.Models.Profile;
|
||||||
using Artemis.Core.Models.Profile.LayerShapes;
|
using Artemis.Core.Models.Profile.LayerShapes;
|
||||||
using Artemis.Core.Models.Surface;
|
using Artemis.Core.Models.Surface;
|
||||||
@ -12,7 +10,6 @@ using Artemis.UI.Extensions;
|
|||||||
using Artemis.UI.Services.Interfaces;
|
using Artemis.UI.Services.Interfaces;
|
||||||
using Artemis.UI.Shared.Services.Interfaces;
|
using Artemis.UI.Shared.Services.Interfaces;
|
||||||
using Stylet;
|
using Stylet;
|
||||||
using Rectangle = Artemis.Core.Models.Profile.LayerShapes.Rectangle;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
||||||
{
|
{
|
||||||
@ -48,7 +45,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
|||||||
get => _shapeGeometry;
|
get => _shapeGeometry;
|
||||||
set => SetAndNotify(ref _shapeGeometry, value);
|
set => SetAndNotify(ref _shapeGeometry, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Rect ViewportRectangle
|
public Rect ViewportRectangle
|
||||||
{
|
{
|
||||||
get => _viewportRectangle;
|
get => _viewportRectangle;
|
||||||
@ -117,7 +114,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
|||||||
private void Update()
|
private void Update()
|
||||||
{
|
{
|
||||||
IsSelected = _profileEditorService.SelectedProfileElement == Layer;
|
IsSelected = _profileEditorService.SelectedProfileElement == Layer;
|
||||||
|
|
||||||
CreateShapeGeometry();
|
CreateShapeGeometry();
|
||||||
CreateViewportRectangle();
|
CreateViewportRectangle();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -56,7 +56,7 @@
|
|||||||
</Entry.SortBy>
|
</Entry.SortBy>
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry DisplayName="All other members" />
|
<Entry DisplayName="All other members" />
|
||||||
<Entry Priority="100" DisplayName="Test Methods">
|
<Entry DisplayName="Test Methods" Priority="100">
|
||||||
<Entry.Match>
|
<Entry.Match>
|
||||||
<And>
|
<And>
|
||||||
<Kind Is="Method" />
|
<Kind Is="Method" />
|
||||||
@ -89,7 +89,7 @@
|
|||||||
</Entry.Match>
|
</Entry.Match>
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry DisplayName="All other members" />
|
<Entry DisplayName="All other members" />
|
||||||
<Entry Priority="100" DisplayName="Test Methods">
|
<Entry DisplayName="Test Methods" Priority="100">
|
||||||
<Entry.Match>
|
<Entry.Match>
|
||||||
<And>
|
<And>
|
||||||
<Kind Is="Method" />
|
<Kind Is="Method" />
|
||||||
@ -102,7 +102,7 @@
|
|||||||
</Entry>
|
</Entry>
|
||||||
</TypePattern>
|
</TypePattern>
|
||||||
<TypePattern DisplayName="Default Pattern">
|
<TypePattern DisplayName="Default Pattern">
|
||||||
<Entry Priority="100" DisplayName="Public Delegates">
|
<Entry DisplayName="Public Delegates" Priority="100">
|
||||||
<Entry.Match>
|
<Entry.Match>
|
||||||
<And>
|
<And>
|
||||||
<Access Is="Public" />
|
<Access Is="Public" />
|
||||||
@ -113,17 +113,6 @@
|
|||||||
<Name />
|
<Name />
|
||||||
</Entry.SortBy>
|
</Entry.SortBy>
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry Priority="100" DisplayName="Public Enums">
|
|
||||||
<Entry.Match>
|
|
||||||
<And>
|
|
||||||
<Access Is="Public" />
|
|
||||||
<Kind Is="Enum" />
|
|
||||||
</And>
|
|
||||||
</Entry.Match>
|
|
||||||
<Entry.SortBy>
|
|
||||||
<Name />
|
|
||||||
</Entry.SortBy>
|
|
||||||
</Entry>
|
|
||||||
<Entry DisplayName="Static Fields and Constants">
|
<Entry DisplayName="Static Fields and Constants">
|
||||||
<Entry.Match>
|
<Entry.Match>
|
||||||
<Or>
|
<Or>
|
||||||
@ -168,7 +157,7 @@
|
|||||||
</Or>
|
</Or>
|
||||||
</Entry.Match>
|
</Entry.Match>
|
||||||
</Entry>
|
</Entry>
|
||||||
<Entry Priority="100" DisplayName="Interface Implementations">
|
<Entry DisplayName="Interface Implementations" Priority="100">
|
||||||
<Entry.Match>
|
<Entry.Match>
|
||||||
<And>
|
<And>
|
||||||
<Kind Is="Member" />
|
<Kind Is="Member" />
|
||||||
@ -189,6 +178,17 @@
|
|||||||
<Kind Is="Type" />
|
<Kind Is="Type" />
|
||||||
</Entry.Match>
|
</Entry.Match>
|
||||||
</Entry>
|
</Entry>
|
||||||
|
<Entry DisplayName="Public Enums" Priority="100">
|
||||||
|
<Entry.Match>
|
||||||
|
<And>
|
||||||
|
<Access Is="Public" />
|
||||||
|
<Kind Is="Enum" />
|
||||||
|
</And>
|
||||||
|
</Entry.Match>
|
||||||
|
<Entry.SortBy>
|
||||||
|
<Name />
|
||||||
|
</Entry.SortBy>
|
||||||
|
</Entry>
|
||||||
</TypePattern>
|
</TypePattern>
|
||||||
</Patterns></s:String>
|
</Patterns></s:String>
|
||||||
<s:Boolean x:Key="/Default/CodeStyle/Generate/=Formatting/@KeyIndexDefined">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeStyle/Generate/=Formatting/@KeyIndexDefined">True</s:Boolean>
|
||||||
|
|||||||
@ -2,7 +2,9 @@
|
|||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using Artemis.Core.Models.Profile;
|
using Artemis.Core.Models.Profile;
|
||||||
using Artemis.Core.Plugins.LayerBrush.Abstract;
|
using Artemis.Core.Plugins.LayerBrush.Abstract;
|
||||||
|
using Artemis.Plugins.LayerBrushes.Color.PropertyGroups;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
using static Artemis.Plugins.LayerBrushes.Color.PropertyGroups.ColorBrushProperties;
|
||||||
|
|
||||||
namespace Artemis.Plugins.LayerBrushes.Color
|
namespace Artemis.Plugins.LayerBrushes.Color
|
||||||
{
|
{
|
||||||
@ -18,7 +20,7 @@ namespace Artemis.Plugins.LayerBrushes.Color
|
|||||||
{
|
{
|
||||||
Layer.RenderPropertiesUpdated += HandleShaderChange;
|
Layer.RenderPropertiesUpdated += HandleShaderChange;
|
||||||
Properties.LayerPropertyBaseValueChanged += HandleShaderChange;
|
Properties.LayerPropertyBaseValueChanged += HandleShaderChange;
|
||||||
Properties.Gradient.BaseValue.PropertyChanged += BaseValueOnPropertyChanged;
|
Properties.Colors.BaseValue.PropertyChanged += BaseValueOnPropertyChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DisableLayerBrush()
|
public override void DisableLayerBrush()
|
||||||
@ -26,9 +28,9 @@ namespace Artemis.Plugins.LayerBrushes.Color
|
|||||||
Layer.RenderPropertiesUpdated -= HandleShaderChange;
|
Layer.RenderPropertiesUpdated -= HandleShaderChange;
|
||||||
Properties.GradientType.BaseValueChanged -= HandleShaderChange;
|
Properties.GradientType.BaseValueChanged -= HandleShaderChange;
|
||||||
Properties.Color.BaseValueChanged -= HandleShaderChange;
|
Properties.Color.BaseValueChanged -= HandleShaderChange;
|
||||||
Properties.GradientTileMode.BaseValueChanged -= HandleShaderChange;
|
Properties.TileMode.BaseValueChanged -= HandleShaderChange;
|
||||||
Properties.GradientRepeat.BaseValueChanged -= HandleShaderChange;
|
Properties.ColorsMultiplier.BaseValueChanged -= HandleShaderChange;
|
||||||
Properties.Gradient.BaseValue.PropertyChanged -= BaseValueOnPropertyChanged;
|
Properties.Colors.BaseValue.PropertyChanged -= BaseValueOnPropertyChanged;
|
||||||
|
|
||||||
_paint?.Dispose();
|
_paint?.Dispose();
|
||||||
_shader?.Dispose();
|
_shader?.Dispose();
|
||||||
@ -39,10 +41,10 @@ namespace Artemis.Plugins.LayerBrushes.Color
|
|||||||
public override void Update(double deltaTime)
|
public override void Update(double deltaTime)
|
||||||
{
|
{
|
||||||
// While rendering a solid, if the color was changed since the last frame, recreate the shader
|
// While rendering a solid, if the color was changed since the last frame, recreate the shader
|
||||||
if (Properties.GradientType.BaseValue == GradientType.Solid && _color != Properties.Color.CurrentValue)
|
if (Properties.GradientType.BaseValue == ColorType.Solid && _color != Properties.Color.CurrentValue)
|
||||||
CreateSolid();
|
CreateSolid();
|
||||||
// While rendering a linear gradient, if the rotation was changed since the last frame, recreate the shader
|
// While rendering a linear gradient, if the rotation was changed since the last frame, recreate the shader
|
||||||
else if (Properties.GradientType.BaseValue == GradientType.LinearGradient && Math.Abs(_linearGradientRotation - Properties.LinearGradientRotation.CurrentValue) > 0.01)
|
else if (Properties.GradientType.BaseValue == ColorType.LinearGradient && Math.Abs(_linearGradientRotation - Properties.LinearGradientRotation.CurrentValue) > 0.01)
|
||||||
CreateLinearGradient();
|
CreateLinearGradient();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -84,16 +86,16 @@ namespace Artemis.Plugins.LayerBrushes.Color
|
|||||||
{
|
{
|
||||||
switch (Properties.GradientType.CurrentValue)
|
switch (Properties.GradientType.CurrentValue)
|
||||||
{
|
{
|
||||||
case GradientType.Solid:
|
case ColorType.Solid:
|
||||||
CreateSolid();
|
CreateSolid();
|
||||||
break;
|
break;
|
||||||
case GradientType.LinearGradient:
|
case ColorType.LinearGradient:
|
||||||
CreateLinearGradient();
|
CreateLinearGradient();
|
||||||
break;
|
break;
|
||||||
case GradientType.RadialGradient:
|
case ColorType.RadialGradient:
|
||||||
CreateRadialGradient();
|
CreateRadialGradient();
|
||||||
break;
|
break;
|
||||||
case GradientType.SweepGradient:
|
case ColorType.SweepGradient:
|
||||||
CreateSweepGradient();
|
CreateSweepGradient();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -120,16 +122,16 @@ namespace Artemis.Plugins.LayerBrushes.Color
|
|||||||
|
|
||||||
private void CreateLinearGradient()
|
private void CreateLinearGradient()
|
||||||
{
|
{
|
||||||
var repeat = Properties.GradientRepeat.CurrentValue;
|
var repeat = Properties.ColorsMultiplier.CurrentValue;
|
||||||
_linearGradientRotation = Properties.LinearGradientRotation.CurrentValue;
|
_linearGradientRotation = Properties.LinearGradientRotation.CurrentValue;
|
||||||
|
|
||||||
_shader?.Dispose();
|
_shader?.Dispose();
|
||||||
_shader = SKShader.CreateLinearGradient(
|
_shader = SKShader.CreateLinearGradient(
|
||||||
new SKPoint(_shaderBounds.Left, _shaderBounds.Top),
|
new SKPoint(_shaderBounds.Left, _shaderBounds.Top),
|
||||||
new SKPoint(_shaderBounds.Right, _shaderBounds.Top),
|
new SKPoint(_shaderBounds.Right, _shaderBounds.Top),
|
||||||
Properties.Gradient.BaseValue.GetColorsArray(repeat),
|
Properties.Colors.BaseValue.GetColorsArray(repeat),
|
||||||
Properties.Gradient.BaseValue.GetPositionsArray(repeat),
|
Properties.Colors.BaseValue.GetPositionsArray(repeat),
|
||||||
Properties.GradientTileMode.CurrentValue,
|
Properties.TileMode.CurrentValue,
|
||||||
SKMatrix.MakeRotationDegrees(_linearGradientRotation, _shaderBounds.Left, _shaderBounds.MidY)
|
SKMatrix.MakeRotationDegrees(_linearGradientRotation, _shaderBounds.Left, _shaderBounds.MidY)
|
||||||
);
|
);
|
||||||
UpdatePaint();
|
UpdatePaint();
|
||||||
@ -137,29 +139,29 @@ namespace Artemis.Plugins.LayerBrushes.Color
|
|||||||
|
|
||||||
private void CreateRadialGradient()
|
private void CreateRadialGradient()
|
||||||
{
|
{
|
||||||
var repeat = Properties.GradientRepeat.CurrentValue;
|
var repeat = Properties.ColorsMultiplier.CurrentValue;
|
||||||
|
|
||||||
_shader?.Dispose();
|
_shader?.Dispose();
|
||||||
_shader = SKShader.CreateRadialGradient(
|
_shader = SKShader.CreateRadialGradient(
|
||||||
new SKPoint(_shaderBounds.MidX, _shaderBounds.MidY),
|
new SKPoint(_shaderBounds.MidX, _shaderBounds.MidY),
|
||||||
Math.Max(_shaderBounds.Width, _shaderBounds.Height) / 2f,
|
Math.Max(_shaderBounds.Width, _shaderBounds.Height) / 2f,
|
||||||
Properties.Gradient.BaseValue.GetColorsArray(repeat),
|
Properties.Colors.BaseValue.GetColorsArray(repeat),
|
||||||
Properties.Gradient.BaseValue.GetPositionsArray(repeat),
|
Properties.Colors.BaseValue.GetPositionsArray(repeat),
|
||||||
Properties.GradientTileMode.CurrentValue
|
Properties.TileMode.CurrentValue
|
||||||
);
|
);
|
||||||
UpdatePaint();
|
UpdatePaint();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void CreateSweepGradient()
|
private void CreateSweepGradient()
|
||||||
{
|
{
|
||||||
var repeat = Properties.GradientRepeat.CurrentValue;
|
var repeat = Properties.ColorsMultiplier.CurrentValue;
|
||||||
|
|
||||||
_shader?.Dispose();
|
_shader?.Dispose();
|
||||||
_shader = SKShader.CreateSweepGradient(
|
_shader = SKShader.CreateSweepGradient(
|
||||||
new SKPoint(_shaderBounds.MidX, _shaderBounds.MidY),
|
new SKPoint(_shaderBounds.MidX, _shaderBounds.MidY),
|
||||||
Properties.Gradient.BaseValue.GetColorsArray(repeat),
|
Properties.Colors.BaseValue.GetColorsArray(repeat),
|
||||||
Properties.Gradient.BaseValue.GetPositionsArray(repeat),
|
Properties.Colors.BaseValue.GetPositionsArray(repeat),
|
||||||
Properties.GradientTileMode.CurrentValue,
|
Properties.TileMode.CurrentValue,
|
||||||
0,
|
0,
|
||||||
360
|
360
|
||||||
);
|
);
|
||||||
|
|||||||
@ -1,115 +0,0 @@
|
|||||||
using System.ComponentModel;
|
|
||||||
using Artemis.Core.Events;
|
|
||||||
using Artemis.Core.Models.Profile;
|
|
||||||
using Artemis.Core.Models.Profile.Colors;
|
|
||||||
using Artemis.Core.Models.Profile.LayerProperties.Attributes;
|
|
||||||
using Artemis.Core.Models.Profile.LayerProperties.Types;
|
|
||||||
using SkiaSharp;
|
|
||||||
|
|
||||||
namespace Artemis.Plugins.LayerBrushes.Color
|
|
||||||
{
|
|
||||||
public class ColorBrushProperties : LayerPropertyGroup
|
|
||||||
{
|
|
||||||
[PropertyDescription(Description = "The type of color brush to draw")]
|
|
||||||
public EnumLayerProperty<GradientType> GradientType { get; set; }
|
|
||||||
|
|
||||||
[PropertyDescription(Description = "How to handle the layer having to stretch beyond it's regular size")]
|
|
||||||
public EnumLayerProperty<SKShaderTileMode> GradientTileMode { get; set; }
|
|
||||||
|
|
||||||
[PropertyDescription(Description = "The color of the brush")]
|
|
||||||
public SKColorLayerProperty Color { get; set; }
|
|
||||||
|
|
||||||
[PropertyDescription(Description = "The gradient of the brush")]
|
|
||||||
public ColorGradientLayerProperty Gradient { get; set; }
|
|
||||||
|
|
||||||
[PropertyDescription(DisableKeyframes = true, Description = "How many times to repeat the colors in the selected gradient", MinInputValue = 0, MaxInputValue = 10)]
|
|
||||||
public IntLayerProperty GradientRepeat { get; set; }
|
|
||||||
|
|
||||||
#region Linear greadient properties
|
|
||||||
|
|
||||||
[PropertyDescription(Name = "Rotation", Description = "Change the rotation of the linear gradient without affecting the rotation of the shape", InputAffix = "°")]
|
|
||||||
public FloatLayerProperty LinearGradientRotation { get; set; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
protected override void PopulateDefaults()
|
|
||||||
{
|
|
||||||
GradientType.DefaultValue = LayerBrushes.Color.GradientType.Solid;
|
|
||||||
Color.DefaultValue = new SKColor(255, 0, 0);
|
|
||||||
Gradient.DefaultValue = ColorGradient.GetUnicornBarf();
|
|
||||||
GradientRepeat.DefaultValue = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void EnableProperties()
|
|
||||||
{
|
|
||||||
GradientType.BaseValueChanged += OnBaseValueChanged;
|
|
||||||
if (ProfileElement is Layer layer)
|
|
||||||
layer.General.ResizeMode.BaseValueChanged += OnBaseValueChanged;
|
|
||||||
|
|
||||||
UpdateVisibility();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override void DisableProperties()
|
|
||||||
{
|
|
||||||
GradientType.BaseValueChanged -= OnBaseValueChanged;
|
|
||||||
if (ProfileElement is Layer layer)
|
|
||||||
layer.General.ResizeMode.BaseValueChanged -= OnBaseValueChanged;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnBaseValueChanged(object sender, LayerPropertyEventArgs e)
|
|
||||||
{
|
|
||||||
UpdateVisibility();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void UpdateVisibility()
|
|
||||||
{
|
|
||||||
var normalRender = false;
|
|
||||||
if (ProfileElement is Layer layer)
|
|
||||||
normalRender = layer.General.ResizeMode.CurrentValue == LayerResizeMode.Normal;
|
|
||||||
|
|
||||||
Color.IsHidden = GradientType.BaseValue != LayerBrushes.Color.GradientType.Solid;
|
|
||||||
Gradient.IsHidden = GradientType.BaseValue == LayerBrushes.Color.GradientType.Solid;
|
|
||||||
GradientRepeat.IsHidden = GradientType.BaseValue == LayerBrushes.Color.GradientType.Solid;
|
|
||||||
|
|
||||||
RadialGradientCenterOffset.IsHidden = GradientType.BaseValue != LayerBrushes.Color.GradientType.RadialGradient;
|
|
||||||
RadialGradientResizeMode.IsHidden = GradientType.BaseValue != LayerBrushes.Color.GradientType.RadialGradient;
|
|
||||||
|
|
||||||
GradientTileMode.IsHidden = normalRender;
|
|
||||||
RadialGradientResizeMode.IsHidden = !normalRender || GradientType.BaseValue != LayerBrushes.Color.GradientType.RadialGradient;
|
|
||||||
}
|
|
||||||
|
|
||||||
#region Radial gradient properties
|
|
||||||
|
|
||||||
[PropertyDescription(Name = "Center offset", Description = "Change the position of the gradient by offsetting it from the center of the layer", InputAffix = "%")]
|
|
||||||
public SKPointLayerProperty RadialGradientCenterOffset { get; set; }
|
|
||||||
|
|
||||||
[PropertyDescription(Name = "Resize mode", Description = "How to make the gradient adjust to scale changes")]
|
|
||||||
public EnumLayerProperty<RadialGradientResizeMode> RadialGradientResizeMode { get; set; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum GradientType
|
|
||||||
{
|
|
||||||
[Description("Solid")]
|
|
||||||
Solid,
|
|
||||||
|
|
||||||
[Description("Linear Gradient")]
|
|
||||||
LinearGradient,
|
|
||||||
|
|
||||||
[Description("Radial Gradient")]
|
|
||||||
RadialGradient,
|
|
||||||
|
|
||||||
[Description("Sweep Gradient")]
|
|
||||||
SweepGradient
|
|
||||||
}
|
|
||||||
|
|
||||||
public enum RadialGradientResizeMode
|
|
||||||
{
|
|
||||||
[Description("Stretch or shrink")]
|
|
||||||
Stretch,
|
|
||||||
|
|
||||||
[Description("Maintain a circle")]
|
|
||||||
MaintainCircle
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -0,0 +1,99 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
using Artemis.Core.Events;
|
||||||
|
using Artemis.Core.Models.Profile;
|
||||||
|
using Artemis.Core.Models.Profile.Colors;
|
||||||
|
using Artemis.Core.Models.Profile.LayerProperties.Attributes;
|
||||||
|
using Artemis.Core.Models.Profile.LayerProperties.Types;
|
||||||
|
using SkiaSharp;
|
||||||
|
|
||||||
|
namespace Artemis.Plugins.LayerBrushes.Color.PropertyGroups
|
||||||
|
{
|
||||||
|
public class ColorBrushProperties : LayerPropertyGroup
|
||||||
|
{
|
||||||
|
[PropertyDescription(Name = "Type", Description = "The type of color brush to draw")]
|
||||||
|
public EnumLayerProperty<ColorType> GradientType { get; set; }
|
||||||
|
|
||||||
|
[PropertyDescription(Description = "How to handle the layer having to stretch beyond it's regular size")]
|
||||||
|
public EnumLayerProperty<SKShaderTileMode> TileMode { get; set; }
|
||||||
|
|
||||||
|
[PropertyDescription(Description = "The color of the brush")]
|
||||||
|
public SKColorLayerProperty Color { get; set; }
|
||||||
|
|
||||||
|
[PropertyDescription(Description = "The gradient of the brush")]
|
||||||
|
public ColorGradientLayerProperty Colors { get; set; }
|
||||||
|
|
||||||
|
[PropertyDescription(Name = "Colors multiplier", Description = "How many times to repeat the colors in the selected gradient", DisableKeyframes = true, MinInputValue = 0, MaxInputValue = 10)]
|
||||||
|
public IntLayerProperty ColorsMultiplier { get; set; }
|
||||||
|
|
||||||
|
[PropertyDescription(Description = "Change the rotation of the linear gradient without affecting the rotation of the shape", InputAffix = "°")]
|
||||||
|
public FloatLayerProperty LinearGradientRotation { get; set; }
|
||||||
|
|
||||||
|
[PropertyGroupDescription(Description = "Advanced radial gradient controls")]
|
||||||
|
public RadialGradientProperties RadialGradient { get; set; }
|
||||||
|
|
||||||
|
protected override void PopulateDefaults()
|
||||||
|
{
|
||||||
|
GradientType.DefaultValue = ColorType.Solid;
|
||||||
|
Color.DefaultValue = new SKColor(255, 0, 0);
|
||||||
|
Colors.DefaultValue = ColorGradient.GetUnicornBarf();
|
||||||
|
ColorsMultiplier.DefaultValue = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void EnableProperties()
|
||||||
|
{
|
||||||
|
GradientType.BaseValueChanged += OnBaseValueChanged;
|
||||||
|
if (ProfileElement is Layer layer)
|
||||||
|
layer.General.ResizeMode.BaseValueChanged += OnBaseValueChanged;
|
||||||
|
|
||||||
|
UpdateVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DisableProperties()
|
||||||
|
{
|
||||||
|
GradientType.BaseValueChanged -= OnBaseValueChanged;
|
||||||
|
if (ProfileElement is Layer layer)
|
||||||
|
layer.General.ResizeMode.BaseValueChanged -= OnBaseValueChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnBaseValueChanged(object sender, LayerPropertyEventArgs e)
|
||||||
|
{
|
||||||
|
UpdateVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateVisibility()
|
||||||
|
{
|
||||||
|
var normalRender = false;
|
||||||
|
if (ProfileElement is Layer layer)
|
||||||
|
normalRender = layer.General.ResizeMode.CurrentValue == LayerResizeMode.Normal;
|
||||||
|
|
||||||
|
// Solid settings
|
||||||
|
Color.IsHidden = GradientType.BaseValue != ColorType.Solid;
|
||||||
|
|
||||||
|
// Gradients settings
|
||||||
|
Colors.IsHidden = GradientType.BaseValue == ColorType.Solid;
|
||||||
|
ColorsMultiplier.IsHidden = GradientType.BaseValue == ColorType.Solid;
|
||||||
|
|
||||||
|
// Linear-gradient settings
|
||||||
|
LinearGradientRotation.IsHidden = GradientType.BaseValue != ColorType.LinearGradient;
|
||||||
|
RadialGradient.IsHidden = GradientType.BaseValue != ColorType.RadialGradient;
|
||||||
|
|
||||||
|
// Normal render settings
|
||||||
|
TileMode.IsHidden = normalRender;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum ColorType
|
||||||
|
{
|
||||||
|
[Description("Solid")]
|
||||||
|
Solid,
|
||||||
|
|
||||||
|
[Description("Linear Gradient")]
|
||||||
|
LinearGradient,
|
||||||
|
|
||||||
|
[Description("Radial Gradient")]
|
||||||
|
RadialGradient,
|
||||||
|
|
||||||
|
[Description("Sweep Gradient")]
|
||||||
|
SweepGradient
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,58 @@
|
|||||||
|
using System.ComponentModel;
|
||||||
|
using Artemis.Core.Events;
|
||||||
|
using Artemis.Core.Models.Profile;
|
||||||
|
using Artemis.Core.Models.Profile.LayerProperties.Attributes;
|
||||||
|
using Artemis.Core.Models.Profile.LayerProperties.Types;
|
||||||
|
|
||||||
|
namespace Artemis.Plugins.LayerBrushes.Color.PropertyGroups
|
||||||
|
{
|
||||||
|
public class RadialGradientProperties : LayerPropertyGroup
|
||||||
|
{
|
||||||
|
[PropertyDescription(Name = "Center offset", Description = "Change the position of the gradient by offsetting it from the center of the layer", InputAffix = "%")]
|
||||||
|
public SKPointLayerProperty CenterOffset { get; set; }
|
||||||
|
|
||||||
|
[PropertyDescription(Name = "Resize mode", Description = "How to make the gradient adjust to scale changes")]
|
||||||
|
public EnumLayerProperty<RadialGradientResizeMode> ResizeMode { get; set; }
|
||||||
|
|
||||||
|
protected override void PopulateDefaults()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void EnableProperties()
|
||||||
|
{
|
||||||
|
if (ProfileElement is Layer layer)
|
||||||
|
layer.General.ResizeMode.BaseValueChanged += OnBaseValueChanged;
|
||||||
|
|
||||||
|
UpdateVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void DisableProperties()
|
||||||
|
{
|
||||||
|
if (ProfileElement is Layer layer)
|
||||||
|
layer.General.ResizeMode.BaseValueChanged -= OnBaseValueChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnBaseValueChanged(object sender, LayerPropertyEventArgs e)
|
||||||
|
{
|
||||||
|
UpdateVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateVisibility()
|
||||||
|
{
|
||||||
|
var normalRender = false;
|
||||||
|
if (ProfileElement is Layer layer)
|
||||||
|
normalRender = layer.General.ResizeMode.CurrentValue == LayerResizeMode.Normal;
|
||||||
|
|
||||||
|
ResizeMode.IsHidden = !normalRender;
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum RadialGradientResizeMode
|
||||||
|
{
|
||||||
|
[Description("Stretch or shrink")]
|
||||||
|
Stretch,
|
||||||
|
|
||||||
|
[Description("Maintain a circle")]
|
||||||
|
MaintainCircle
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -23,5 +23,9 @@ namespace Artemis.Plugins.LayerBrushes.ColorRgbNet
|
|||||||
protected override void EnableProperties()
|
protected override void EnableProperties()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void DisableProperties()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,6 +49,10 @@ namespace Artemis.Plugins.LayerBrushes.Noise
|
|||||||
UpdateVisibility();
|
UpdateVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void DisableProperties()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateVisibility()
|
private void UpdateVisibility()
|
||||||
{
|
{
|
||||||
GradientColor.IsHidden = ColorType.BaseValue != ColorMappingType.Gradient;
|
GradientColor.IsHidden = ColorType.BaseValue != ColorMappingType.Gradient;
|
||||||
|
|||||||
@ -18,7 +18,7 @@ namespace Artemis.Plugins.LayerEffects.Filter
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
private void UpdateVisibility()
|
protected override void DisableProperties()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -25,5 +25,9 @@ namespace Artemis.Plugins.LayerEffects.Filter
|
|||||||
{
|
{
|
||||||
ColorMatrix.IsHidden = true;
|
ColorMatrix.IsHidden = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void DisableProperties()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -16,5 +16,9 @@ namespace Artemis.Plugins.LayerEffects.Filter
|
|||||||
protected override void EnableProperties()
|
protected override void EnableProperties()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void DisableProperties()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -16,5 +16,9 @@ namespace Artemis.Plugins.LayerEffects.Filter
|
|||||||
protected override void EnableProperties()
|
protected override void EnableProperties()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void DisableProperties()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -25,5 +25,9 @@ namespace Artemis.Plugins.LayerEffects.Filter
|
|||||||
protected override void EnableProperties()
|
protected override void EnableProperties()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void DisableProperties()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -16,5 +16,9 @@ namespace Artemis.Plugins.LayerEffects.Filter
|
|||||||
protected override void EnableProperties()
|
protected override void EnableProperties()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void DisableProperties()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -43,5 +43,9 @@ namespace Artemis.Plugins.LayerEffects.Filter
|
|||||||
protected override void EnableProperties()
|
protected override void EnableProperties()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override void DisableProperties()
|
||||||
|
{
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user