mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Merge branch 'development'
This commit is contained in:
commit
67e1c20500
@ -13,7 +13,7 @@ namespace Artemis.Core;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ColorGradient : IList<ColorGradientStop>, IList, INotifyCollectionChanged
|
public class ColorGradient : IList<ColorGradientStop>, IList, INotifyCollectionChanged
|
||||||
{
|
{
|
||||||
private static readonly SKColor[] FastLedRainbow =
|
private static readonly SKColor[] FAST_LED_RAINBOW =
|
||||||
{
|
{
|
||||||
new(0xFFFF0000), // Red
|
new(0xFFFF0000), // Red
|
||||||
new(0xFFFF9900), // Orange
|
new(0xFFFF9900), // Orange
|
||||||
@ -27,8 +27,25 @@ public class ColorGradient : IList<ColorGradientStop>, IList, INotifyCollectionC
|
|||||||
};
|
};
|
||||||
|
|
||||||
private readonly List<ColorGradientStop> _stops;
|
private readonly List<ColorGradientStop> _stops;
|
||||||
|
private SKColor[] _colors = Array.Empty<SKColor>();
|
||||||
|
private float[] _positions = Array.Empty<float>();
|
||||||
|
private bool _dirty = true;
|
||||||
private bool _updating;
|
private bool _updating;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an array containing the colors of the color gradient.
|
||||||
|
/// <para/>
|
||||||
|
/// Note: Making changes to this array will not be reflected on the gradient, is is essentially read-only.
|
||||||
|
/// </summary>
|
||||||
|
public SKColor[] Colors => GetColors();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets an array containing the positions of colors of the color gradient.
|
||||||
|
/// <para/>
|
||||||
|
/// Note: Making changes to this array will not be reflected on the gradient, is is essentially read-only.
|
||||||
|
/// </summary>
|
||||||
|
public float[] Positions => GetPositions();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the <see cref="ColorGradient" /> class
|
/// Creates a new instance of the <see cref="ColorGradient" /> class
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -81,8 +98,12 @@ public class ColorGradient : IList<ColorGradientStop>, IList, INotifyCollectionC
|
|||||||
/// last color
|
/// last color
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <returns>An array containing each color in the gradient</returns>
|
/// <returns>An array containing each color in the gradient</returns>
|
||||||
|
[Obsolete("Use the Colors property instead", true)]
|
||||||
public SKColor[] GetColorsArray(int timesToRepeat = 0, bool seamless = false)
|
public SKColor[] GetColorsArray(int timesToRepeat = 0, bool seamless = false)
|
||||||
{
|
{
|
||||||
|
if (timesToRepeat == 0 && !seamless)
|
||||||
|
return Colors;
|
||||||
|
|
||||||
List<SKColor> result = new();
|
List<SKColor> result = new();
|
||||||
if (timesToRepeat == 0)
|
if (timesToRepeat == 0)
|
||||||
result = this.Select(c => c.Color).ToList();
|
result = this.Select(c => c.Color).ToList();
|
||||||
@ -105,8 +126,12 @@ public class ColorGradient : IList<ColorGradientStop>, IList, INotifyCollectionC
|
|||||||
/// last color
|
/// last color
|
||||||
/// </param>
|
/// </param>
|
||||||
/// <returns>An array containing a position for each color between 0.0 and 1.0</returns>
|
/// <returns>An array containing a position for each color between 0.0 and 1.0</returns>
|
||||||
|
[Obsolete("Use the Positions property instead", true)]
|
||||||
public float[] GetPositionsArray(int timesToRepeat = 0, bool seamless = false)
|
public float[] GetPositionsArray(int timesToRepeat = 0, bool seamless = false)
|
||||||
{
|
{
|
||||||
|
if (timesToRepeat == 0 && seamless)
|
||||||
|
return Positions;
|
||||||
|
|
||||||
List<float> result = new();
|
List<float> result = new();
|
||||||
if (timesToRepeat == 0)
|
if (timesToRepeat == 0)
|
||||||
{
|
{
|
||||||
@ -147,8 +172,12 @@ public class ColorGradient : IList<ColorGradientStop>, IList, INotifyCollectionC
|
|||||||
/// A boolean indicating whether to make the gradient seamless by adding the first color behind the
|
/// A boolean indicating whether to make the gradient seamless by adding the first color behind the
|
||||||
/// last color
|
/// last color
|
||||||
/// </param>
|
/// </param>
|
||||||
|
[Obsolete("Use GetColor(float position) instead.", true)]
|
||||||
public SKColor GetColor(float position, int timesToRepeat = 0, bool seamless = false)
|
public SKColor GetColor(float position, int timesToRepeat = 0, bool seamless = false)
|
||||||
{
|
{
|
||||||
|
if (timesToRepeat == 0 && !seamless)
|
||||||
|
return GetColor(position);
|
||||||
|
|
||||||
if (!this.Any())
|
if (!this.Any())
|
||||||
return new SKColor(255, 255, 255);
|
return new SKColor(255, 255, 255);
|
||||||
|
|
||||||
@ -194,30 +223,38 @@ public class ColorGradient : IList<ColorGradientStop>, IList, INotifyCollectionC
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a new ColorGradient with colors looping through the HSV-spectrum
|
/// Gets a color at any position between 0.0 and 1.0 using interpolation
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static ColorGradient GetUnicornBarf()
|
/// <param name="position">A position between 0.0 and 1.0</param>
|
||||||
|
public SKColor GetColor(float position)
|
||||||
{
|
{
|
||||||
ColorGradient gradient = new();
|
if (_stops.Count == 0)
|
||||||
for (int index = 0; index < FastLedRainbow.Length; index++)
|
return SKColors.Transparent;
|
||||||
{
|
|
||||||
SKColor skColor = FastLedRainbow[index];
|
|
||||||
float position = 1f / (FastLedRainbow.Length - 1f) * index;
|
|
||||||
gradient.Add(new ColorGradientStop(skColor, position));
|
|
||||||
}
|
|
||||||
|
|
||||||
return gradient;
|
if (_stops.Count == 1)
|
||||||
}
|
return _stops[0].Color;
|
||||||
|
|
||||||
/// <summary>
|
if (position <= 0)
|
||||||
/// Gets a new ColorGradient with random colors from the HSV-spectrum
|
return _stops[0].Color;
|
||||||
/// </summary>
|
|
||||||
/// <param name="stops">The amount of stops to add</param>
|
if (position >= 1)
|
||||||
public ColorGradient GetRandom(int stops)
|
return _stops[^1].Color;
|
||||||
{
|
|
||||||
ColorGradient gradient = new();
|
//find the first stop after the position
|
||||||
gradient.Randomize(stops);
|
int stop2Index = _stops.FindIndex(s => s.Position >= position);
|
||||||
return gradient;
|
//if the position is before the first stop, return that color
|
||||||
|
if (stop2Index == 0)
|
||||||
|
return _stops[0].Color;
|
||||||
|
|
||||||
|
//interpolate between that one and the one before
|
||||||
|
int stop1Index = stop2Index - 1;
|
||||||
|
|
||||||
|
ColorGradientStop stop1 = _stops[stop1Index];
|
||||||
|
ColorGradientStop stop2 = _stops[stop2Index];
|
||||||
|
|
||||||
|
//calculate how far between the 2 stops we want to interpolate
|
||||||
|
float positionBetween = (position - stop1.Position) / (stop2.Position - stop1.Position);
|
||||||
|
return stop1.Color.Interpolate(stop2.Color, positionBetween);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -243,7 +280,7 @@ public class ColorGradient : IList<ColorGradientStop>, IList, INotifyCollectionC
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_updating = false;
|
_updating = false;
|
||||||
Sort();
|
Update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -289,7 +326,7 @@ public class ColorGradient : IList<ColorGradientStop>, IList, INotifyCollectionC
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_updating = false;
|
_updating = false;
|
||||||
Sort();
|
Update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -307,7 +344,7 @@ public class ColorGradient : IList<ColorGradientStop>, IList, INotifyCollectionC
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_updating = false;
|
_updating = false;
|
||||||
Sort();
|
Update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -332,7 +369,7 @@ public class ColorGradient : IList<ColorGradientStop>, IList, INotifyCollectionC
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_updating = false;
|
_updating = false;
|
||||||
Sort();
|
Update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,17 +395,96 @@ public class ColorGradient : IList<ColorGradientStop>, IList, INotifyCollectionC
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
_updating = false;
|
_updating = false;
|
||||||
Sort();
|
Update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Interpolates a color gradient between the this gradient and the provided <paramref name="targetValue"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="targetValue">The second color gradient.</param>
|
||||||
|
/// <param name="progress">A value between 0 and 1.</param>
|
||||||
|
/// <returns>The interpolated color gradient.</returns>
|
||||||
|
public ColorGradient Interpolate(ColorGradient targetValue, float progress)
|
||||||
|
{
|
||||||
|
ColorGradient interpolated = new(this);
|
||||||
|
|
||||||
|
// Add new stops
|
||||||
|
if (targetValue.Count > interpolated.Count)
|
||||||
|
{
|
||||||
|
// Prefer the stops on a vacant position
|
||||||
|
foreach (ColorGradientStop stop in targetValue.Take(targetValue.Count - interpolated.Count))
|
||||||
|
interpolated.Add(new ColorGradientStop(GetColor(stop.Position), stop.Position));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Interpolate stops
|
||||||
|
int index = 0;
|
||||||
|
foreach (ColorGradientStop stop in interpolated.ToList())
|
||||||
|
{
|
||||||
|
if (index < targetValue.Count)
|
||||||
|
{
|
||||||
|
ColorGradientStop targetStop = targetValue[index];
|
||||||
|
stop.Interpolate(targetStop, progress);
|
||||||
|
}
|
||||||
|
// Interpolate stops not on the target gradient
|
||||||
|
else
|
||||||
|
{
|
||||||
|
stop.Color = stop.Color.Interpolate(targetValue.GetColor(stop.Position), progress);
|
||||||
|
}
|
||||||
|
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return interpolated;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a new ColorGradient with colors looping through the HSV-spectrum
|
||||||
|
/// </summary>
|
||||||
|
public static ColorGradient GetUnicornBarf()
|
||||||
|
{
|
||||||
|
ColorGradient gradient = new();
|
||||||
|
for (int index = 0; index < FAST_LED_RAINBOW.Length; index++)
|
||||||
|
{
|
||||||
|
SKColor skColor = FAST_LED_RAINBOW[index];
|
||||||
|
float position = 1f / (FAST_LED_RAINBOW.Length - 1f) * index;
|
||||||
|
gradient.Add(new ColorGradientStop(skColor, position));
|
||||||
|
}
|
||||||
|
|
||||||
|
return gradient;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets a new ColorGradient with random colors from the HSV-spectrum
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="stops">The amount of stops to add</param>
|
||||||
|
public static ColorGradient GetRandom(int stops)
|
||||||
|
{
|
||||||
|
ColorGradient gradient = new();
|
||||||
|
gradient.Randomize(stops);
|
||||||
|
return gradient;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs when any of the stops has changed in some way
|
/// Occurs when any of the stops has changed in some way
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler? StopChanged;
|
public event EventHandler? StopChanged;
|
||||||
|
|
||||||
internal void Sort()
|
private void ItemOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
|
Update();
|
||||||
|
OnStopChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnStopChanged()
|
||||||
|
{
|
||||||
|
StopChanged?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
_dirty = true;
|
||||||
|
|
||||||
if (_updating)
|
if (_updating)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
@ -387,15 +503,24 @@ public class ColorGradient : IList<ColorGradientStop>, IList, INotifyCollectionC
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ItemOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
private float[] GetPositions()
|
||||||
{
|
{
|
||||||
Sort();
|
if (!_dirty)
|
||||||
OnStopChanged();
|
return _positions;
|
||||||
|
|
||||||
|
_colors = this.Select(s => s.Color).ToArray();
|
||||||
|
_positions = this.Select(s => s.Position).ToArray();
|
||||||
|
return _positions;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void OnStopChanged()
|
private SKColor[] GetColors()
|
||||||
{
|
{
|
||||||
StopChanged?.Invoke(this, EventArgs.Empty);
|
if (!_dirty)
|
||||||
|
return _colors;
|
||||||
|
|
||||||
|
_colors = this.Select(s => s.Color).ToArray();
|
||||||
|
_positions = this.Select(s => s.Position).ToArray();
|
||||||
|
return _colors;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Equality members
|
#region Equality members
|
||||||
@ -473,7 +598,7 @@ public class ColorGradient : IList<ColorGradientStop>, IList, INotifyCollectionC
|
|||||||
item.PropertyChanged += ItemOnPropertyChanged;
|
item.PropertyChanged += ItemOnPropertyChanged;
|
||||||
|
|
||||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, _stops.IndexOf(item)));
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, _stops.IndexOf(item)));
|
||||||
Sort();
|
Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -583,7 +708,7 @@ public class ColorGradient : IList<ColorGradientStop>, IList, INotifyCollectionC
|
|||||||
{
|
{
|
||||||
_stops.Insert(index, item);
|
_stops.Insert(index, item);
|
||||||
item.PropertyChanged += ItemOnPropertyChanged;
|
item.PropertyChanged += ItemOnPropertyChanged;
|
||||||
Sort();
|
Update();
|
||||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, _stops.IndexOf(item)));
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item, _stops.IndexOf(item)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -608,7 +733,7 @@ public class ColorGradient : IList<ColorGradientStop>, IList, INotifyCollectionC
|
|||||||
oldValue.PropertyChanged -= ItemOnPropertyChanged;
|
oldValue.PropertyChanged -= ItemOnPropertyChanged;
|
||||||
_stops[index] = value;
|
_stops[index] = value;
|
||||||
_stops[index].PropertyChanged += ItemOnPropertyChanged;
|
_stops[index].PropertyChanged += ItemOnPropertyChanged;
|
||||||
Sort();
|
Update();
|
||||||
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, oldValue));
|
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Replace, value, oldValue));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -626,36 +751,4 @@ public class ColorGradient : IList<ColorGradientStop>, IList, INotifyCollectionC
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
public ColorGradient Interpolate(ColorGradient targetValue, float progress)
|
|
||||||
{
|
|
||||||
ColorGradient interpolated = new(this);
|
|
||||||
|
|
||||||
// Add new stops
|
|
||||||
if (targetValue.Count > interpolated.Count)
|
|
||||||
{
|
|
||||||
// Prefer the stops on a vacant position
|
|
||||||
foreach (ColorGradientStop stop in targetValue.Take(targetValue.Count - interpolated.Count))
|
|
||||||
interpolated.Add(new ColorGradientStop(GetColor(stop.Position), stop.Position));
|
|
||||||
}
|
|
||||||
// Interpolate stops
|
|
||||||
int index = 0;
|
|
||||||
foreach (ColorGradientStop stop in interpolated.ToList())
|
|
||||||
{
|
|
||||||
if (index < targetValue.Count)
|
|
||||||
{
|
|
||||||
ColorGradientStop targetStop = targetValue[index];
|
|
||||||
stop.Interpolate(targetStop, progress);
|
|
||||||
}
|
|
||||||
// Interpolate stops not on the target gradient
|
|
||||||
else
|
|
||||||
{
|
|
||||||
stop.Color = stop.Color.Interpolate(targetValue.GetColor(stop.Position), progress);
|
|
||||||
}
|
|
||||||
|
|
||||||
index++;
|
|
||||||
}
|
|
||||||
|
|
||||||
return interpolated;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -94,11 +94,17 @@ public class ColorGradientStop : CorePropertyChanged
|
|||||||
return stopPosition;
|
return stopPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
/// <summary>
|
||||||
|
/// Interpolates a color gradient stop between the this stop and the provided <paramref name="targetValue"/>.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="targetValue">The second stop.</param>
|
||||||
|
/// <param name="progress">A value between 0 and 1.</param>
|
||||||
|
/// <returns>The interpolated color gradient stop.</returns>
|
||||||
public void Interpolate(ColorGradientStop targetValue, float progress)
|
public void Interpolate(ColorGradientStop targetValue, float progress)
|
||||||
{
|
{
|
||||||
Color = Color.Interpolate(targetValue.Color, progress);
|
Color = Color.Interpolate(targetValue.Color, progress);
|
||||||
Position = Position + ((targetValue.Position - Position) * progress);
|
Position += (targetValue.Position - Position) * progress;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
@ -273,7 +273,7 @@ public abstract class RenderProfileElement : ProfileElement
|
|||||||
// If no descriptor was found and there was no existing placeholder, create a placeholder
|
// If no descriptor was found and there was no existing placeholder, create a placeholder
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
descriptor = PlaceholderLayerEffectDescriptor.Create(layerEffectEntity.ProviderId);
|
descriptor = PlaceholderLayerEffectDescriptor.Create();
|
||||||
layerEffect = descriptor.CreateInstance(this, layerEffectEntity);
|
layerEffect = descriptor.CreateInstance(this, layerEffectEntity);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -286,7 +286,7 @@ public abstract class RenderProfileElement : ProfileElement
|
|||||||
if (index == -1)
|
if (index == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
LayerEffectDescriptor descriptor = PlaceholderLayerEffectDescriptor.Create(layerEffect.ProviderId);
|
LayerEffectDescriptor descriptor = PlaceholderLayerEffectDescriptor.Create();
|
||||||
BaseLayerEffect placeholder = descriptor.CreateInstance(this, layerEffect.LayerEffectEntity);
|
BaseLayerEffect placeholder = descriptor.CreateInstance(this, layerEffect.LayerEffectEntity);
|
||||||
_layerEffects[index] = placeholder;
|
_layerEffects[index] = placeholder;
|
||||||
layerEffect.Dispose();
|
layerEffect.Dispose();
|
||||||
@ -299,7 +299,7 @@ public abstract class RenderProfileElement : ProfileElement
|
|||||||
if (index == -1)
|
if (index == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
LayerEffectDescriptor? descriptor = LayerEffectStore.Get(placeholder.OriginalEntity.ProviderId, placeholder.PlaceholderFor)?.LayerEffectDescriptor;
|
LayerEffectDescriptor? descriptor = LayerEffectStore.Get(placeholder.OriginalEntity.ProviderId, placeholder.OriginalEntity.EffectType)?.LayerEffectDescriptor;
|
||||||
if (descriptor == null)
|
if (descriptor == null)
|
||||||
throw new ArtemisCoreException("Can't replace a placeholder effect because the real effect isn't available.");
|
throw new ArtemisCoreException("Can't replace a placeholder effect because the real effect isn't available.");
|
||||||
|
|
||||||
@ -324,7 +324,7 @@ public abstract class RenderProfileElement : ProfileElement
|
|||||||
private void LayerEffectStoreOnLayerEffectRemoved(object? sender, LayerEffectStoreEvent e)
|
private void LayerEffectStoreOnLayerEffectRemoved(object? sender, LayerEffectStoreEvent e)
|
||||||
{
|
{
|
||||||
// Find effects that just got disabled and replace them with placeholders
|
// Find effects that just got disabled and replace them with placeholders
|
||||||
List<BaseLayerEffect> affectedLayerEffects = _layerEffects.Where(ef => ef.ProviderId == e.Registration.PluginFeature.Id).ToList();
|
List<BaseLayerEffect> affectedLayerEffects = _layerEffects.Where(e.Registration.Matches).ToList();
|
||||||
|
|
||||||
if (!affectedLayerEffects.Any())
|
if (!affectedLayerEffects.Any())
|
||||||
return;
|
return;
|
||||||
@ -338,7 +338,7 @@ public abstract class RenderProfileElement : ProfileElement
|
|||||||
{
|
{
|
||||||
// Find placeholders that just got enabled and replace them with real effects
|
// Find placeholders that just got enabled and replace them with real effects
|
||||||
List<PlaceholderLayerEffect> affectedPlaceholders = LayerEffects
|
List<PlaceholderLayerEffect> affectedPlaceholders = LayerEffects
|
||||||
.Where(l => l is PlaceholderLayerEffect ph && ph.OriginalEntity.ProviderId == e.Registration.PluginFeature.Id)
|
.Where(l => l is PlaceholderLayerEffect ph && e.Registration.Matches(ph))
|
||||||
.Cast<PlaceholderLayerEffect>()
|
.Cast<PlaceholderLayerEffect>()
|
||||||
.ToList();
|
.ToList();
|
||||||
|
|
||||||
|
|||||||
@ -164,12 +164,7 @@ public abstract class BaseLayerEffect : BreakableModel, IDisposable, IStorageMod
|
|||||||
// Not only is this needed to initialize properties on the layer effects, it also prevents implementing anything
|
// Not only is this needed to initialize properties on the layer effects, it also prevents implementing anything
|
||||||
// but LayerEffect<T> outside the core
|
// but LayerEffect<T> outside the core
|
||||||
internal abstract void Initialize();
|
internal abstract void Initialize();
|
||||||
|
|
||||||
internal virtual string GetEffectTypeName()
|
|
||||||
{
|
|
||||||
return GetType().Name;
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void InternalUpdate(Timeline timeline)
|
internal void InternalUpdate(Timeline timeline)
|
||||||
{
|
{
|
||||||
BaseProperties?.Update(timeline);
|
BaseProperties?.Update(timeline);
|
||||||
@ -220,20 +215,23 @@ public abstract class BaseLayerEffect : BreakableModel, IDisposable, IStorageMod
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Load()
|
public void Load()
|
||||||
{
|
{
|
||||||
HasBeenRenamed = LayerEffectEntity.HasBeenRenamed;
|
|
||||||
Name = HasBeenRenamed ? LayerEffectEntity.Name : Descriptor.DisplayName;
|
Name = HasBeenRenamed ? LayerEffectEntity.Name : Descriptor.DisplayName;
|
||||||
|
HasBeenRenamed = LayerEffectEntity.HasBeenRenamed;
|
||||||
Order = LayerEffectEntity.Order;
|
Order = LayerEffectEntity.Order;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Save()
|
public void Save()
|
||||||
{
|
{
|
||||||
LayerEffectEntity.ProviderId = Descriptor.Provider.Id;
|
|
||||||
LayerEffectEntity.EffectType = GetType().FullName;
|
|
||||||
LayerEffectEntity.Name = Name;
|
LayerEffectEntity.Name = Name;
|
||||||
LayerEffectEntity.HasBeenRenamed = HasBeenRenamed;
|
LayerEffectEntity.HasBeenRenamed = HasBeenRenamed;
|
||||||
LayerEffectEntity.Order = Order;
|
LayerEffectEntity.Order = Order;
|
||||||
|
|
||||||
|
if (Descriptor.IsPlaceholder)
|
||||||
|
return;
|
||||||
|
|
||||||
|
LayerEffectEntity.ProviderId = Descriptor.Provider.Id;
|
||||||
|
LayerEffectEntity.EffectType = GetType().FullName;
|
||||||
BaseProperties?.ApplyToEntity();
|
BaseProperties?.ApplyToEntity();
|
||||||
LayerEffectEntity.PropertyGroup = BaseProperties?.PropertyGroupEntity;
|
LayerEffectEntity.PropertyGroup = BaseProperties?.PropertyGroupEntity;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -19,9 +19,9 @@ public class LayerEffectDescriptor
|
|||||||
Provider = provider ?? throw new ArgumentNullException(nameof(provider));
|
Provider = provider ?? throw new ArgumentNullException(nameof(provider));
|
||||||
}
|
}
|
||||||
|
|
||||||
internal LayerEffectDescriptor(string placeholderFor, LayerEffectProvider provider)
|
private LayerEffectDescriptor(LayerEffectProvider provider)
|
||||||
{
|
{
|
||||||
PlaceholderFor = placeholderFor ?? throw new ArgumentNullException(nameof(placeholderFor));
|
IsPlaceholder = true;
|
||||||
Provider = provider ?? throw new ArgumentNullException(nameof(provider));
|
Provider = provider ?? throw new ArgumentNullException(nameof(provider));
|
||||||
DisplayName = "Missing effect";
|
DisplayName = "Missing effect";
|
||||||
Description = "This effect could not be loaded";
|
Description = "This effect could not be loaded";
|
||||||
@ -55,16 +55,21 @@ public class LayerEffectDescriptor
|
|||||||
public LayerEffectProvider Provider { get; }
|
public LayerEffectProvider Provider { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the GUID this descriptor is acting as a placeholder for. If null, this descriptor is not a placeholder
|
/// Gets a boolean indicating whether this descriptor is a placeholder descriptor.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? PlaceholderFor { get; }
|
public bool IsPlaceholder { get; }
|
||||||
|
|
||||||
|
internal static LayerEffectDescriptor CreatePlaceholder(LayerEffectProvider provider)
|
||||||
|
{
|
||||||
|
return new LayerEffectDescriptor(provider);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates an instance of the described effect and applies it to the render element
|
/// Creates an instance of the described effect and applies it to the render element
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public BaseLayerEffect CreateInstance(RenderProfileElement renderElement, LayerEffectEntity? entity)
|
public BaseLayerEffect CreateInstance(RenderProfileElement renderElement, LayerEffectEntity? entity)
|
||||||
{
|
{
|
||||||
if (PlaceholderFor != null)
|
if (IsPlaceholder)
|
||||||
{
|
{
|
||||||
if (entity == null)
|
if (entity == null)
|
||||||
throw new ArtemisCoreException("Cannot create a placeholder for a layer effect that wasn't loaded from an entity");
|
throw new ArtemisCoreException("Cannot create a placeholder for a layer effect that wasn't loaded from an entity");
|
||||||
@ -97,10 +102,10 @@ public class LayerEffectDescriptor
|
|||||||
|
|
||||||
private BaseLayerEffect CreatePlaceHolderInstance(RenderProfileElement renderElement, LayerEffectEntity entity)
|
private BaseLayerEffect CreatePlaceHolderInstance(RenderProfileElement renderElement, LayerEffectEntity entity)
|
||||||
{
|
{
|
||||||
if (PlaceholderFor == null)
|
if (!IsPlaceholder)
|
||||||
throw new ArtemisCoreException("Cannot create a placeholder instance using a layer effect descriptor that is not a placeholder for anything");
|
throw new ArtemisCoreException("Cannot create a placeholder instance using a layer effect descriptor that is not a placeholder for anything");
|
||||||
|
|
||||||
PlaceholderLayerEffect effect = new(entity, PlaceholderFor)
|
PlaceholderLayerEffect effect = new(entity)
|
||||||
{
|
{
|
||||||
ProfileElement = renderElement,
|
ProfileElement = renderElement,
|
||||||
Descriptor = this
|
Descriptor = this
|
||||||
|
|||||||
@ -8,10 +8,9 @@ namespace Artemis.Core.LayerEffects.Placeholder;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal class PlaceholderLayerEffect : LayerEffect<PlaceholderProperties>
|
internal class PlaceholderLayerEffect : LayerEffect<PlaceholderProperties>
|
||||||
{
|
{
|
||||||
internal PlaceholderLayerEffect(LayerEffectEntity originalEntity, string placeholderFor)
|
internal PlaceholderLayerEffect(LayerEffectEntity originalEntity)
|
||||||
{
|
{
|
||||||
OriginalEntity = originalEntity;
|
OriginalEntity = originalEntity;
|
||||||
PlaceholderFor = placeholderFor;
|
|
||||||
|
|
||||||
LayerEffectEntity = originalEntity;
|
LayerEffectEntity = originalEntity;
|
||||||
Order = OriginalEntity.Order;
|
Order = OriginalEntity.Order;
|
||||||
@ -19,8 +18,6 @@ internal class PlaceholderLayerEffect : LayerEffect<PlaceholderProperties>
|
|||||||
HasBeenRenamed = OriginalEntity.HasBeenRenamed;
|
HasBeenRenamed = OriginalEntity.HasBeenRenamed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public string PlaceholderFor { get; }
|
|
||||||
|
|
||||||
internal LayerEffectEntity OriginalEntity { get; }
|
internal LayerEffectEntity OriginalEntity { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -47,11 +44,6 @@ internal class PlaceholderLayerEffect : LayerEffect<PlaceholderProperties>
|
|||||||
public override void PostProcess(SKCanvas canvas, SKRect bounds, SKPaint paint)
|
public override void PostProcess(SKCanvas canvas, SKRect bounds, SKPaint paint)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
internal override string GetEffectTypeName()
|
|
||||||
{
|
|
||||||
return OriginalEntity.EffectType;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -2,9 +2,9 @@
|
|||||||
|
|
||||||
internal static class PlaceholderLayerEffectDescriptor
|
internal static class PlaceholderLayerEffectDescriptor
|
||||||
{
|
{
|
||||||
public static LayerEffectDescriptor Create(string missingProviderId)
|
public static LayerEffectDescriptor Create()
|
||||||
{
|
{
|
||||||
LayerEffectDescriptor descriptor = new(missingProviderId, Constants.EffectPlaceholderPlugin);
|
LayerEffectDescriptor descriptor = LayerEffectDescriptor.CreatePlaceholder(Constants.EffectPlaceholderPlugin);
|
||||||
return descriptor;
|
return descriptor;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -170,11 +170,13 @@ internal class RgbService : IRgbService
|
|||||||
|
|
||||||
public void AddDeviceProvider(IRGBDeviceProvider deviceProvider)
|
public void AddDeviceProvider(IRGBDeviceProvider deviceProvider)
|
||||||
{
|
{
|
||||||
|
_logger.Verbose("[AddDeviceProvider] Pausing rendering to add {DeviceProvider}", deviceProvider.GetType().Name);
|
||||||
bool changedRenderPaused = SetRenderPaused(true);
|
bool changedRenderPaused = SetRenderPaused(true);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
List<ArtemisDevice> toRemove = _devices.Where(a => deviceProvider.Devices.Any(d => a.RgbDevice == d)).ToList();
|
List<ArtemisDevice> toRemove = _devices.Where(a => deviceProvider.Devices.Any(d => a.RgbDevice == d)).ToList();
|
||||||
|
_logger.Verbose("[AddDeviceProvider] Removing {Count} old device(s)", toRemove.Count);
|
||||||
Surface.Detach(toRemove.Select(d => d.RgbDevice));
|
Surface.Detach(toRemove.Select(d => d.RgbDevice));
|
||||||
foreach (ArtemisDevice device in toRemove)
|
foreach (ArtemisDevice device in toRemove)
|
||||||
RemoveDevice(device);
|
RemoveDevice(device);
|
||||||
@ -189,8 +191,10 @@ internal class RgbService : IRgbService
|
|||||||
_logger.Warning(e.Exception, "Device provider {deviceProvider} threw non-critical exception", deviceProvider.GetType().Name);
|
_logger.Warning(e.Exception, "Device provider {deviceProvider} threw non-critical exception", deviceProvider.GetType().Name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
_logger.Verbose("[AddDeviceProvider] Initializing device provider");
|
||||||
deviceProvider.Exception += DeviceProviderOnException;
|
deviceProvider.Exception += DeviceProviderOnException;
|
||||||
deviceProvider.Initialize();
|
deviceProvider.Initialize();
|
||||||
|
_logger.Verbose("[AddDeviceProvider] Attaching devices of device provider");
|
||||||
Surface.Attach(deviceProvider.Devices);
|
Surface.Attach(deviceProvider.Devices);
|
||||||
deviceProvider.Exception -= DeviceProviderOnException;
|
deviceProvider.Exception -= DeviceProviderOnException;
|
||||||
if (providerExceptions.Count == 1)
|
if (providerExceptions.Count == 1)
|
||||||
@ -220,7 +224,10 @@ internal class RgbService : IRgbService
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
_logger.Verbose("[AddDeviceProvider] Updating the LED group");
|
||||||
UpdateLedGroup();
|
UpdateLedGroup();
|
||||||
|
|
||||||
|
_logger.Verbose("[AddDeviceProvider] Resuming rendering after adding {DeviceProvider}", deviceProvider.GetType().Name);
|
||||||
if (changedRenderPaused)
|
if (changedRenderPaused)
|
||||||
SetRenderPaused(false);
|
SetRenderPaused(false);
|
||||||
}
|
}
|
||||||
@ -228,11 +235,13 @@ internal class RgbService : IRgbService
|
|||||||
|
|
||||||
public void RemoveDeviceProvider(IRGBDeviceProvider deviceProvider)
|
public void RemoveDeviceProvider(IRGBDeviceProvider deviceProvider)
|
||||||
{
|
{
|
||||||
|
_logger.Verbose("[RemoveDeviceProvider] Pausing rendering to remove {DeviceProvider}", deviceProvider.GetType().Name);
|
||||||
bool changedRenderPaused = SetRenderPaused(true);
|
bool changedRenderPaused = SetRenderPaused(true);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
List<ArtemisDevice> toRemove = _devices.Where(a => deviceProvider.Devices.Any(d => a.RgbDevice == d)).ToList();
|
List<ArtemisDevice> toRemove = _devices.Where(a => deviceProvider.Devices.Any(d => a.RgbDevice == d)).ToList();
|
||||||
|
_logger.Verbose("[RemoveDeviceProvider] Removing {Count} old device(s)", toRemove.Count);
|
||||||
Surface.Detach(toRemove.Select(d => d.RgbDevice));
|
Surface.Detach(toRemove.Select(d => d.RgbDevice));
|
||||||
foreach (ArtemisDevice device in toRemove)
|
foreach (ArtemisDevice device in toRemove)
|
||||||
RemoveDevice(device);
|
RemoveDevice(device);
|
||||||
@ -246,7 +255,10 @@ internal class RgbService : IRgbService
|
|||||||
}
|
}
|
||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
|
_logger.Verbose("[RemoveDeviceProvider] Updating the LED group");
|
||||||
UpdateLedGroup();
|
UpdateLedGroup();
|
||||||
|
|
||||||
|
_logger.Verbose("[RemoveDeviceProvider] Resuming rendering after adding {DeviceProvider}", deviceProvider.GetType().Name);
|
||||||
if (changedRenderPaused)
|
if (changedRenderPaused)
|
||||||
SetRenderPaused(false);
|
SetRenderPaused(false);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using Artemis.Core.LayerEffects;
|
using Artemis.Core.LayerEffects;
|
||||||
|
using Artemis.Core.LayerEffects.Placeholder;
|
||||||
|
|
||||||
namespace Artemis.Core;
|
namespace Artemis.Core;
|
||||||
|
|
||||||
@ -37,4 +38,25 @@ public class LayerEffectRegistration
|
|||||||
if (IsInStore)
|
if (IsInStore)
|
||||||
LayerEffectStore.Remove(this);
|
LayerEffectStore.Remove(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the provided placeholder matches this event.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="placeholder">The placeholder to check</param>
|
||||||
|
/// <returns><see langword="true" /> if the placeholder is for the provided layer effect registration, otherwise <see langword="false" />.</returns>
|
||||||
|
internal bool Matches(PlaceholderLayerEffect placeholder)
|
||||||
|
{
|
||||||
|
return placeholder.OriginalEntity.ProviderId == PluginFeature.Id &&
|
||||||
|
placeholder.OriginalEntity.EffectType == LayerEffectDescriptor.LayerEffectType?.FullName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Determines whether the provided layer effect matches this event.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="layerEffect">The layer effect to check</param>
|
||||||
|
/// <returns><see langword="true" /> if the placeholder is for the provided layer effect registration, otherwise <see langword="false" />.</returns>
|
||||||
|
internal bool Matches(BaseLayerEffect layerEffect)
|
||||||
|
{
|
||||||
|
return layerEffect.Descriptor == LayerEffectDescriptor;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -432,5 +432,30 @@ public static class NumericExtensions
|
|||||||
return new Numeric(sum);
|
return new Numeric(sum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Subtracts the numerics in the provided collection
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The remainder of all numerics subtracted from one another in the collection</returns>
|
||||||
|
/// <exception cref="ArgumentNullException"></exception>
|
||||||
|
public static Numeric Subtract(this IEnumerable<Numeric> source)
|
||||||
|
{
|
||||||
|
if (source == null) throw new ArgumentNullException(nameof(source));
|
||||||
|
|
||||||
|
float subtraction = 0f;
|
||||||
|
bool first = true;
|
||||||
|
foreach (float v in source)
|
||||||
|
{
|
||||||
|
if (first)
|
||||||
|
{
|
||||||
|
subtraction = v;
|
||||||
|
first = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
subtraction -= v;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Numeric(subtraction);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
@ -78,10 +78,17 @@ public class NodeData
|
|||||||
/// </returns>
|
/// </returns>
|
||||||
public bool MatchesSearch(string text)
|
public bool MatchesSearch(string text)
|
||||||
{
|
{
|
||||||
text = text.Trim();
|
string rawText = text.Trim();
|
||||||
return Name.Contains(text, StringComparison.InvariantCultureIgnoreCase) ||
|
text = text.Trim().TrimStart('!');
|
||||||
Description.Contains(text, StringComparison.InvariantCultureIgnoreCase) ||
|
|
||||||
Category.Contains(text, StringComparison.InvariantCultureIgnoreCase);
|
if (rawText.StartsWith("!!"))
|
||||||
|
return Name.Equals(text, StringComparison.InvariantCultureIgnoreCase);
|
||||||
|
else if (rawText.StartsWith("!"))
|
||||||
|
return Name.StartsWith(text, StringComparison.InvariantCultureIgnoreCase);
|
||||||
|
else
|
||||||
|
return Name.Contains(text, StringComparison.InvariantCultureIgnoreCase) ||
|
||||||
|
Description.Contains(text, StringComparison.InvariantCultureIgnoreCase) ||
|
||||||
|
Category.Contains(text, StringComparison.InvariantCultureIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Properties & Fields
|
#region Properties & Fields
|
||||||
|
|||||||
@ -26,6 +26,8 @@ public sealed class InputPin<T> : Pin
|
|||||||
{
|
{
|
||||||
if (ConnectedTo.Count > 0 && ConnectedTo[0].PinValue is T value)
|
if (ConnectedTo.Count > 0 && ConnectedTo[0].PinValue is T value)
|
||||||
Value = value;
|
Value = value;
|
||||||
|
else
|
||||||
|
Value = default;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@ -67,7 +67,7 @@ public class M0021GradientNodes : IStorageMigration
|
|||||||
List<ProfileEntity> profiles = repository.Query<ProfileEntity>().ToList();
|
List<ProfileEntity> profiles = repository.Query<ProfileEntity>().ToList();
|
||||||
foreach (ProfileEntity profileEntity in profiles)
|
foreach (ProfileEntity profileEntity in profiles)
|
||||||
{
|
{
|
||||||
foreach (LayerEntity layer in profileEntity.Layers)
|
foreach (LayerEntity layer in profileEntity.Layers.Where(le => le.LayerBrush != null))
|
||||||
MigrateDataBinding(layer.LayerBrush.PropertyGroup);
|
MigrateDataBinding(layer.LayerBrush.PropertyGroup);
|
||||||
|
|
||||||
repository.Update(profileEntity);
|
repository.Update(profileEntity);
|
||||||
|
|||||||
@ -0,0 +1,34 @@
|
|||||||
|
using Artemis.Core;
|
||||||
|
|
||||||
|
namespace Artemis.VisualScripting.Nodes.Mathematics;
|
||||||
|
|
||||||
|
[Node("Subtract", "Subtracts the connected numeric values.", "Mathematics", InputType = typeof(Numeric), OutputType = typeof(Numeric))]
|
||||||
|
public class SubtractNumericsNode : Node
|
||||||
|
{
|
||||||
|
#region Constructors
|
||||||
|
|
||||||
|
public SubtractNumericsNode()
|
||||||
|
{
|
||||||
|
Values = CreateInputPinCollection<Numeric>("Values", 2);
|
||||||
|
Remainder = CreateOutputPin<Numeric>("Remainder");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Methods
|
||||||
|
|
||||||
|
public override void Evaluate()
|
||||||
|
{
|
||||||
|
Remainder.Value = Values.Values.Subtract();
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Properties & Fields
|
||||||
|
|
||||||
|
public InputPinCollection<Numeric> Values { get; }
|
||||||
|
|
||||||
|
public OutputPin<Numeric> Remainder { get; }
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user