mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-31 09:43:46 +00:00
Merge branch 'development'
This commit is contained in:
commit
c37284b821
@ -16,7 +16,7 @@ namespace Artemis.Core
|
|||||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||||
public static int RoundToInt(this float number)
|
public static int RoundToInt(this float number)
|
||||||
{
|
{
|
||||||
return (int) Math.Round(number, MidpointRounding.AwayFromZero);
|
return (int) MathF.Round(number, MidpointRounding.AwayFromZero);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -25,11 +25,16 @@ namespace Artemis.Core
|
|||||||
public static SKRect ToSKRect(this Rectangle rectangle)
|
public static SKRect ToSKRect(this Rectangle rectangle)
|
||||||
{
|
{
|
||||||
return SKRect.Create(
|
return SKRect.Create(
|
||||||
(float) rectangle.Location.X,
|
rectangle.Location.X,
|
||||||
(float) rectangle.Location.Y,
|
rectangle.Location.Y,
|
||||||
(float) rectangle.Size.Width,
|
rectangle.Size.Width,
|
||||||
(float) rectangle.Size.Height
|
rectangle.Size.Height
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static SKRectI ToSKRectI(this Rectangle rectangle)
|
||||||
|
{
|
||||||
|
return SKRectI.Round(ToSKRect(rectangle));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -10,6 +10,19 @@ namespace Artemis.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ColorGradient : CorePropertyChanged
|
public class ColorGradient : CorePropertyChanged
|
||||||
{
|
{
|
||||||
|
private static readonly SKColor[] FastLedRainbow =
|
||||||
|
{
|
||||||
|
new(0xFFFF0000), // Red
|
||||||
|
new(0xFFFF9900), // Orange
|
||||||
|
new(0xFFFFFF00), // Yellow
|
||||||
|
new(0xFF00FF00), // Green
|
||||||
|
new(0xFF00FF7E), // Aqua
|
||||||
|
new(0xFF0078FF), // Blue
|
||||||
|
new(0xFF9E22FF), // Purple
|
||||||
|
new(0xFFFF34AE), // Pink
|
||||||
|
new(0xFFFF0000) // and back to Red
|
||||||
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the <see cref="ColorGradient" /> class
|
/// Creates a new instance of the <see cref="ColorGradient" /> class
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -31,9 +44,9 @@ namespace Artemis.Core
|
|||||||
public SKColor[] GetColorsArray(int timesToRepeat = 0)
|
public SKColor[] GetColorsArray(int timesToRepeat = 0)
|
||||||
{
|
{
|
||||||
if (timesToRepeat == 0)
|
if (timesToRepeat == 0)
|
||||||
return Stops.OrderBy(c => c.Position).Select(c => c.Color).ToArray();
|
return Stops.Select(c => c.Color).ToArray();
|
||||||
|
|
||||||
List<SKColor> colors = Stops.OrderBy(c => c.Position).Select(c => c.Color).ToList();
|
List<SKColor> colors = Stops.Select(c => c.Color).ToList();
|
||||||
List<SKColor> result = new();
|
List<SKColor> result = new();
|
||||||
|
|
||||||
for (int i = 0; i <= timesToRepeat; i++)
|
for (int i = 0; i <= timesToRepeat; i++)
|
||||||
@ -53,10 +66,10 @@ namespace Artemis.Core
|
|||||||
public float[] GetPositionsArray(int timesToRepeat = 0)
|
public float[] GetPositionsArray(int timesToRepeat = 0)
|
||||||
{
|
{
|
||||||
if (timesToRepeat == 0)
|
if (timesToRepeat == 0)
|
||||||
return Stops.OrderBy(c => c.Position).Select(c => c.Position).ToArray();
|
return Stops.Select(c => c.Position).ToArray();
|
||||||
|
|
||||||
// Create stops and a list of divided stops
|
// Create stops and a list of divided stops
|
||||||
List<float> stops = Stops.OrderBy(c => c.Position).Select(c => c.Position / (timesToRepeat + 1)).ToList();
|
List<float> stops = Stops.Select(c => c.Position / (timesToRepeat + 1)).ToList();
|
||||||
List<float> result = new();
|
List<float> result = new();
|
||||||
|
|
||||||
// For each repeat cycle, add the base stops to the end result
|
// For each repeat cycle, add the base stops to the end result
|
||||||
@ -74,6 +87,7 @@ namespace Artemis.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public void OnColorValuesUpdated()
|
public void OnColorValuesUpdated()
|
||||||
{
|
{
|
||||||
|
Stops.Sort((a, b) => a.Position.CompareTo(b.Position));
|
||||||
OnPropertyChanged(nameof(Stops));
|
OnPropertyChanged(nameof(Stops));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -86,7 +100,7 @@ namespace Artemis.Core
|
|||||||
if (!Stops.Any())
|
if (!Stops.Any())
|
||||||
return SKColor.Empty;
|
return SKColor.Empty;
|
||||||
|
|
||||||
ColorGradientStop[] stops = Stops.OrderBy(x => x.Position).ToArray();
|
ColorGradientStop[] stops = Stops.ToArray();
|
||||||
if (position <= 0) return stops[0].Color;
|
if (position <= 0) return stops[0].Color;
|
||||||
if (position >= 1) return stops[^1].Color;
|
if (position >= 1) return stops[^1].Color;
|
||||||
ColorGradientStop left = stops[0];
|
ColorGradientStop left = stops[0];
|
||||||
@ -119,13 +133,12 @@ namespace Artemis.Core
|
|||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
public static ColorGradient GetUnicornBarf()
|
public static ColorGradient GetUnicornBarf()
|
||||||
{
|
{
|
||||||
const int amount = 8;
|
|
||||||
ColorGradient gradient = new();
|
ColorGradient gradient = new();
|
||||||
|
for (int index = 0; index < FastLedRainbow.Length; index++)
|
||||||
for (int i = 0; i <= amount; i++)
|
|
||||||
{
|
{
|
||||||
float percent = i / (float)amount;
|
SKColor skColor = FastLedRainbow[index];
|
||||||
gradient.Stops.Add(new ColorGradientStop(SKColor.FromHsv(360f * percent, 100, 100), percent));
|
float position = 1f / (FastLedRainbow.Length - 1f) * index;
|
||||||
|
gradient.Stops.Add(new ColorGradientStop(skColor, position));
|
||||||
}
|
}
|
||||||
|
|
||||||
return gradient;
|
return gradient;
|
||||||
|
|||||||
@ -63,7 +63,10 @@ namespace Artemis.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public Easings.Functions EasingFunction { get; set; }
|
public Easings.Functions EasingFunction { get; set; }
|
||||||
|
|
||||||
internal DataBindingEntity Entity { get; }
|
/// <summary>
|
||||||
|
/// Gets the data binding entity this data binding uses for persistent storage
|
||||||
|
/// </summary>
|
||||||
|
public DataBindingEntity Entity { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the current value of the data binding
|
/// Gets the current value of the data binding
|
||||||
@ -100,6 +103,25 @@ namespace Artemis.Core
|
|||||||
return Registration?.Getter.Method.ReturnType;
|
return Registration?.Getter.Method.ReturnType;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">
|
||||||
|
/// <see langword="true" /> to release both managed and unmanaged resources;
|
||||||
|
/// <see langword="false" /> to release only unmanaged resources.
|
||||||
|
/// </param>
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing)
|
||||||
|
{
|
||||||
|
_disposed = true;
|
||||||
|
|
||||||
|
if (Registration != null)
|
||||||
|
Registration.DataBinding = null;
|
||||||
|
DataBindingMode?.Dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void ResetEasing(TProperty value)
|
private void ResetEasing(TProperty value)
|
||||||
{
|
{
|
||||||
_previousValue = GetInterpolatedValue();
|
_previousValue = GetInterpolatedValue();
|
||||||
@ -192,27 +214,6 @@ namespace Artemis.Core
|
|||||||
_reapplyValue = true;
|
_reapplyValue = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region IDisposable
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="disposing">
|
|
||||||
/// <see langword="true" /> to release both managed and unmanaged resources;
|
|
||||||
/// <see langword="false" /> to release only unmanaged resources.
|
|
||||||
/// </param>
|
|
||||||
protected virtual void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing)
|
|
||||||
{
|
|
||||||
_disposed = true;
|
|
||||||
|
|
||||||
if (Registration != null)
|
|
||||||
Registration.DataBinding = null;
|
|
||||||
DataBindingMode?.Dispose();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
@ -220,8 +221,6 @@ namespace Artemis.Core
|
|||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region Mode management
|
#region Mode management
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -245,6 +244,16 @@ namespace Artemis.Core
|
|||||||
ApplyDataBindingMode();
|
ApplyDataBindingMode();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Replaces the current data binding mode with one based on the provided data binding mode entity
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dataBindingModeEntity">The data binding mode entity to base the new data binding mode upon</param>
|
||||||
|
public void ApplyDataBindingEntity(IDataBindingModeEntity dataBindingModeEntity)
|
||||||
|
{
|
||||||
|
Entity.DataBindingMode = dataBindingModeEntity;
|
||||||
|
ApplyDataBindingMode();
|
||||||
|
}
|
||||||
|
|
||||||
private void ApplyDataBindingMode()
|
private void ApplyDataBindingMode()
|
||||||
{
|
{
|
||||||
DataBindingMode?.Dispose();
|
DataBindingMode?.Dispose();
|
||||||
|
|||||||
@ -29,9 +29,13 @@ namespace Artemis.Core
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[DataModelProperty(Name = "Last event trigger", Description = "The time at which the event last triggered")]
|
[DataModelProperty(Name = "Last trigger", Description = "The time at which the event last triggered")]
|
||||||
public DateTime LastTrigger { get; private set; }
|
public DateTime LastTrigger { get; private set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[DataModelProperty(Name = "Time since trigger", Description = "The time that has passed since the last trigger")]
|
||||||
|
public TimeSpan TimeSinceLastTrigger => DateTime.Now - LastTrigger;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the event arguments of the last time the event was triggered
|
/// Gets the event arguments of the last time the event was triggered
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -85,6 +89,7 @@ namespace Artemis.Core
|
|||||||
public Type ArgumentsType => typeof(T);
|
public Type ArgumentsType => typeof(T);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
[DataModelIgnore]
|
||||||
public string TriggerPastParticiple => "triggered";
|
public string TriggerPastParticiple => "triggered";
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -147,14 +152,18 @@ namespace Artemis.Core
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[DataModelProperty(Name = "Last event trigger", Description = "The time at which the event last triggered")]
|
[DataModelProperty(Name = "Last trigger", Description = "The time at which the event last triggered")]
|
||||||
public DateTime LastTrigger { get; private set; }
|
public DateTime LastTrigger { get; private set; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
[DataModelProperty(Name = "Time since trigger", Description = "The time that has passed since the last trigger")]
|
||||||
|
public TimeSpan TimeSinceLastTrigger => DateTime.Now - LastTrigger;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the event arguments of the last time the event was triggered
|
/// Gets the event arguments of the last time the event was triggered
|
||||||
/// </summary>
|
/// </summary>
|
||||||
[DataModelProperty(Description = "The arguments of the last time this event triggered")]
|
[DataModelProperty(Description = "The arguments of the last time this event triggered")]
|
||||||
public DataModelEventArgs? LastEventArguments { get; private set; }
|
public DataModelEventArgs? LastTriggerArguments { get; private set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[DataModelProperty(Description = "The total amount of times this event has triggered since the module was activated")]
|
[DataModelProperty(Description = "The total amount of times this event has triggered since the module was activated")]
|
||||||
@ -174,7 +183,7 @@ namespace Artemis.Core
|
|||||||
{
|
{
|
||||||
DataModelEventArgs eventArgs = new() {TriggerTime = DateTime.Now};
|
DataModelEventArgs eventArgs = new() {TriggerTime = DateTime.Now};
|
||||||
|
|
||||||
LastEventArguments = eventArgs;
|
LastTriggerArguments = eventArgs;
|
||||||
LastTrigger = DateTime.Now;
|
LastTrigger = DateTime.Now;
|
||||||
TriggerCount++;
|
TriggerCount++;
|
||||||
|
|
||||||
@ -201,6 +210,7 @@ namespace Artemis.Core
|
|||||||
public Type ArgumentsType => typeof(DataModelEventArgs);
|
public Type ArgumentsType => typeof(DataModelEventArgs);
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
[DataModelIgnore]
|
||||||
public string TriggerPastParticiple => "triggered";
|
public string TriggerPastParticiple => "triggered";
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -217,7 +227,7 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[DataModelIgnore]
|
[DataModelIgnore]
|
||||||
public DataModelEventArgs? LastEventArgumentsUntyped => LastEventArguments;
|
public DataModelEventArgs? LastEventArgumentsUntyped => LastTriggerArguments;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
[DataModelIgnore]
|
[DataModelIgnore]
|
||||||
|
|||||||
@ -13,6 +13,11 @@ namespace Artemis.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
DateTime LastTrigger { get; }
|
DateTime LastTrigger { get; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the time that has passed since the last trigger
|
||||||
|
/// </summary>
|
||||||
|
TimeSpan TimeSinceLastTrigger { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the amount of times the event was triggered
|
/// Gets the amount of times the event was triggered
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -14,6 +14,7 @@ namespace Artemis.Core
|
|||||||
public T? LastValue { get; private set; }
|
public T? LastValue { get; private set; }
|
||||||
public T? CurrentValue { get; private set; }
|
public T? CurrentValue { get; private set; }
|
||||||
public DateTime LastTrigger { get; private set; }
|
public DateTime LastTrigger { get; private set; }
|
||||||
|
public TimeSpan TimeSinceLastTrigger => DateTime.Now - LastTrigger;
|
||||||
public int TriggerCount { get; private set; }
|
public int TriggerCount { get; private set; }
|
||||||
public Type ArgumentsType { get; } = typeof(DataModelValueChangedEventArgs<T>);
|
public Type ArgumentsType { get; } = typeof(DataModelValueChangedEventArgs<T>);
|
||||||
public string TriggerPastParticiple => "changed";
|
public string TriggerPastParticiple => "changed";
|
||||||
|
|||||||
@ -4,7 +4,6 @@ using System.Linq;
|
|||||||
using Artemis.Core.LayerEffects;
|
using Artemis.Core.LayerEffects;
|
||||||
using Artemis.Storage.Entities.Profile;
|
using Artemis.Storage.Entities.Profile;
|
||||||
using Artemis.Storage.Entities.Profile.Abstract;
|
using Artemis.Storage.Entities.Profile.Abstract;
|
||||||
using Newtonsoft.Json;
|
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace Artemis.Core
|
namespace Artemis.Core
|
||||||
@ -153,8 +152,10 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
SKPath path = new() {FillType = SKPathFillType.Winding};
|
SKPath path = new() {FillType = SKPathFillType.Winding};
|
||||||
foreach (ProfileElement child in Children)
|
foreach (ProfileElement child in Children)
|
||||||
|
{
|
||||||
if (child is RenderProfileElement effectChild && effectChild.Path != null)
|
if (child is RenderProfileElement effectChild && effectChild.Path != null)
|
||||||
path.AddPath(effectChild.Path);
|
path.AddPath(effectChild.Path);
|
||||||
|
}
|
||||||
|
|
||||||
Path = path;
|
Path = path;
|
||||||
|
|
||||||
@ -168,7 +169,7 @@ namespace Artemis.Core
|
|||||||
#region Rendering
|
#region Rendering
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Render(SKCanvas canvas, SKPoint basePosition)
|
public override void Render(SKCanvas canvas, SKPointI basePosition)
|
||||||
{
|
{
|
||||||
if (Disposed)
|
if (Disposed)
|
||||||
throw new ObjectDisposedException("Folder");
|
throw new ObjectDisposedException("Folder");
|
||||||
@ -192,12 +193,12 @@ namespace Artemis.Core
|
|||||||
SKPaint layerPaint = new();
|
SKPaint layerPaint = new();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
SKRect rendererBounds = SKRect.Create(0, 0, Path.Bounds.Width, Path.Bounds.Height);
|
SKRectI rendererBounds = SKRectI.Create(0, 0, Bounds.Width, Bounds.Height);
|
||||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
||||||
baseLayerEffect.PreProcess(canvas, rendererBounds, layerPaint);
|
baseLayerEffect.PreProcess(canvas, rendererBounds, layerPaint);
|
||||||
|
|
||||||
canvas.SaveLayer(layerPaint);
|
canvas.SaveLayer(layerPaint);
|
||||||
canvas.Translate(Path.Bounds.Left - basePosition.X, Path.Bounds.Top - basePosition.Y);
|
canvas.Translate(Bounds.Left - basePosition.X, Bounds.Top - basePosition.Y);
|
||||||
|
|
||||||
// If required, apply the opacity override of the module to the root folder
|
// If required, apply the opacity override of the module to the root folder
|
||||||
if (IsRootFolder && Profile.Module.OpacityOverride < 1)
|
if (IsRootFolder && Profile.Module.OpacityOverride < 1)
|
||||||
@ -212,7 +213,7 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
// Iterate the children in reverse because the first layer must be rendered last to end up on top
|
// Iterate the children in reverse because the first layer must be rendered last to end up on top
|
||||||
for (int index = Children.Count - 1; index > -1; index--)
|
for (int index = Children.Count - 1; index > -1; index--)
|
||||||
Children[index].Render(canvas, new SKPoint(Path.Bounds.Left, Path.Bounds.Top));
|
Children[index].Render(canvas, new SKPointI(Bounds.Left, Bounds.Top));
|
||||||
|
|
||||||
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
foreach (BaseLayerEffect baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
||||||
baseLayerEffect.PostProcess(canvas, rendererBounds, layerPaint);
|
baseLayerEffect.PostProcess(canvas, rendererBounds, layerPaint);
|
||||||
|
|||||||
@ -277,7 +277,7 @@ namespace Artemis.Core
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Render(SKCanvas canvas, SKPoint basePosition)
|
public override void Render(SKCanvas canvas, SKPointI basePosition)
|
||||||
{
|
{
|
||||||
if (Disposed)
|
if (Disposed)
|
||||||
throw new ObjectDisposedException("Layer");
|
throw new ObjectDisposedException("Layer");
|
||||||
@ -312,7 +312,7 @@ namespace Artemis.Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderTimeline(Timeline timeline, SKCanvas canvas, SKPoint basePosition)
|
private void RenderTimeline(Timeline timeline, SKCanvas canvas, SKPointI basePosition)
|
||||||
{
|
{
|
||||||
if (Path == null || LayerBrush == null)
|
if (Path == null || LayerBrush == null)
|
||||||
throw new ArtemisCoreException("The layer is not yet ready for rendering");
|
throw new ArtemisCoreException("The layer is not yet ready for rendering");
|
||||||
@ -329,12 +329,11 @@ namespace Artemis.Core
|
|||||||
try
|
try
|
||||||
{
|
{
|
||||||
canvas.Save();
|
canvas.Save();
|
||||||
canvas.Translate(Path.Bounds.Left - basePosition.X, Path.Bounds.Top - basePosition.Y);
|
canvas.Translate(Bounds.Left - basePosition.X, Bounds.Top - basePosition.Y);
|
||||||
using SKPath clipPath = new(Path);
|
using SKPath clipPath = new(Path);
|
||||||
clipPath.Transform(SKMatrix.CreateTranslation(Path.Bounds.Left * -1, Path.Bounds.Top * -1));
|
clipPath.Transform(SKMatrix.CreateTranslation(Bounds.Left * -1, Bounds.Top * -1));
|
||||||
canvas.ClipPath(clipPath);
|
canvas.ClipPath(clipPath, SKClipOperation.Intersect, true);
|
||||||
|
SKRectI layerBounds = SKRectI.Create(0, 0, Bounds.Width, Bounds.Height);
|
||||||
SKRect layerBounds = SKRect.Create(0, 0, Path.Bounds.Width, Path.Bounds.Height);
|
|
||||||
|
|
||||||
// Apply blend mode and color
|
// Apply blend mode and color
|
||||||
layerPaint.BlendMode = General.BlendMode.CurrentValue;
|
layerPaint.BlendMode = General.BlendMode.CurrentValue;
|
||||||
@ -435,7 +434,7 @@ namespace Artemis.Core
|
|||||||
OnRenderPropertiesUpdated();
|
OnRenderPropertiesUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
internal SKPoint GetLayerAnchorPosition(SKPath layerPath, bool applyTranslation, bool zeroBased)
|
internal SKPoint GetLayerAnchorPosition(bool applyTranslation, bool zeroBased)
|
||||||
{
|
{
|
||||||
if (Disposed)
|
if (Disposed)
|
||||||
throw new ObjectDisposedException("Layer");
|
throw new ObjectDisposedException("Layer");
|
||||||
@ -444,14 +443,14 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
// Start at the center of the shape
|
// Start at the center of the shape
|
||||||
SKPoint position = zeroBased
|
SKPoint position = zeroBased
|
||||||
? new SKPoint(layerPath.Bounds.MidX - layerPath.Bounds.Left, layerPath.Bounds.MidY - layerPath.Bounds.Top)
|
? new SKPointI(Bounds.MidX - Bounds.Left, Bounds.MidY - Bounds.Top)
|
||||||
: new SKPoint(layerPath.Bounds.MidX, layerPath.Bounds.MidY);
|
: new SKPointI(Bounds.MidX, Bounds.MidY);
|
||||||
|
|
||||||
// Apply translation
|
// Apply translation
|
||||||
if (applyTranslation)
|
if (applyTranslation)
|
||||||
{
|
{
|
||||||
position.X += positionProperty.X * layerPath.Bounds.Width;
|
position.X += positionProperty.X * Bounds.Width;
|
||||||
position.Y += positionProperty.Y * layerPath.Bounds.Height;
|
position.Y += positionProperty.Y * Bounds.Height;
|
||||||
}
|
}
|
||||||
|
|
||||||
return position;
|
return position;
|
||||||
@ -479,7 +478,7 @@ namespace Artemis.Core
|
|||||||
SKSize sizeProperty = Transform.Scale.CurrentValue;
|
SKSize sizeProperty = Transform.Scale.CurrentValue;
|
||||||
float rotationProperty = Transform.Rotation.CurrentValue;
|
float rotationProperty = Transform.Rotation.CurrentValue;
|
||||||
|
|
||||||
SKPoint anchorPosition = GetLayerAnchorPosition(Path, true, zeroBased);
|
SKPoint anchorPosition = GetLayerAnchorPosition(true, zeroBased);
|
||||||
SKPoint anchorProperty = Transform.AnchorPoint.CurrentValue;
|
SKPoint anchorProperty = Transform.AnchorPoint.CurrentValue;
|
||||||
|
|
||||||
// Translation originates from the unscaled center of the shape and is tied to the anchor
|
// Translation originates from the unscaled center of the shape and is tied to the anchor
|
||||||
|
|||||||
@ -81,7 +81,7 @@ namespace Artemis.Core
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Render(SKCanvas canvas, SKPoint basePosition)
|
public override void Render(SKCanvas canvas, SKPointI basePosition)
|
||||||
{
|
{
|
||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -104,7 +104,7 @@ namespace Artemis.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Renders the element
|
/// Renders the element
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract void Render(SKCanvas canvas, SKPoint basePosition);
|
public abstract void Render(SKCanvas canvas, SKPointI basePosition);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Resets the internal state of the element
|
/// Resets the internal state of the element
|
||||||
|
|||||||
@ -16,6 +16,9 @@ namespace Artemis.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public abstract class RenderProfileElement : ProfileElement
|
public abstract class RenderProfileElement : ProfileElement
|
||||||
{
|
{
|
||||||
|
private SKPath? _path;
|
||||||
|
private SKRectI _bounds;
|
||||||
|
|
||||||
internal RenderProfileElement(Profile profile) : base(profile)
|
internal RenderProfileElement(Profile profile) : base(profile)
|
||||||
{
|
{
|
||||||
Timeline = new Timeline();
|
Timeline = new Timeline();
|
||||||
@ -113,7 +116,6 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
#region Properties
|
#region Properties
|
||||||
|
|
||||||
private SKPath? _path;
|
|
||||||
internal abstract RenderElementEntity RenderElementEntity { get; }
|
internal abstract RenderElementEntity RenderElementEntity { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -141,14 +143,14 @@ namespace Artemis.Core
|
|||||||
SetAndNotify(ref _path, value);
|
SetAndNotify(ref _path, value);
|
||||||
// I can't really be sure about the performance impact of calling Bounds often but
|
// I can't really be sure about the performance impact of calling Bounds often but
|
||||||
// SkiaSharp calls SkiaApi.sk_path_get_bounds (Handle, &rect); which sounds expensive
|
// SkiaSharp calls SkiaApi.sk_path_get_bounds (Handle, &rect); which sounds expensive
|
||||||
Bounds = value?.Bounds ?? SKRect.Empty;
|
Bounds = SKRectI.Round(value?.Bounds ?? SKRect.Empty);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The bounds of this entity
|
/// The bounds of this entity
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SKRect Bounds
|
public SKRectI Bounds
|
||||||
{
|
{
|
||||||
get => _bounds;
|
get => _bounds;
|
||||||
private set => SetAndNotify(ref _bounds, value);
|
private set => SetAndNotify(ref _bounds, value);
|
||||||
@ -158,7 +160,6 @@ namespace Artemis.Core
|
|||||||
#region Property group expansion
|
#region Property group expansion
|
||||||
|
|
||||||
internal List<string> ExpandedPropertyGroups;
|
internal List<string> ExpandedPropertyGroups;
|
||||||
private SKRect _bounds;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Determines whether the provided property group is expanded
|
/// Determines whether the provided property group is expanded
|
||||||
|
|||||||
@ -337,6 +337,7 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
Layout = layout;
|
Layout = layout;
|
||||||
Layout.ApplyDevice(this);
|
Layout.ApplyDevice(this);
|
||||||
|
CalculateRenderProperties();
|
||||||
OnDeviceUpdated();
|
OnDeviceUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -8,8 +8,8 @@ namespace Artemis.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ArtemisLed : CorePropertyChanged
|
public class ArtemisLed : CorePropertyChanged
|
||||||
{
|
{
|
||||||
private SKRect _absoluteRectangle;
|
private SKRectI _absoluteRectangle;
|
||||||
private SKRect _rectangle;
|
private SKRectI _rectangle;
|
||||||
|
|
||||||
internal ArtemisLed(Led led, ArtemisDevice device)
|
internal ArtemisLed(Led led, ArtemisDevice device)
|
||||||
{
|
{
|
||||||
@ -31,7 +31,7 @@ namespace Artemis.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the rectangle covering the LED positioned relative to the<see cref="Device" />
|
/// Gets the rectangle covering the LED positioned relative to the<see cref="Device" />
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SKRect Rectangle
|
public SKRectI Rectangle
|
||||||
{
|
{
|
||||||
get => _rectangle;
|
get => _rectangle;
|
||||||
private set => SetAndNotify(ref _rectangle, value);
|
private set => SetAndNotify(ref _rectangle, value);
|
||||||
@ -40,7 +40,7 @@ namespace Artemis.Core
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the rectangle covering the LED
|
/// Gets the rectangle covering the LED
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SKRect AbsoluteRectangle
|
public SKRectI AbsoluteRectangle
|
||||||
{
|
{
|
||||||
get => _absoluteRectangle;
|
get => _absoluteRectangle;
|
||||||
private set => SetAndNotify(ref _absoluteRectangle, value);
|
private set => SetAndNotify(ref _absoluteRectangle, value);
|
||||||
@ -59,8 +59,8 @@ namespace Artemis.Core
|
|||||||
|
|
||||||
internal void CalculateRectangles()
|
internal void CalculateRectangles()
|
||||||
{
|
{
|
||||||
Rectangle = RgbLed.Boundary.ToSKRect();
|
Rectangle = RgbLed.Boundary.ToSKRectI();
|
||||||
AbsoluteRectangle = RgbLed.AbsoluteBoundary.ToSKRect();
|
AbsoluteRectangle = RgbLed.AbsoluteBoundary.ToSKRectI();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -177,7 +177,7 @@ namespace Artemis.Core.Modules
|
|||||||
lock (_lock)
|
lock (_lock)
|
||||||
{
|
{
|
||||||
// Render the profile
|
// Render the profile
|
||||||
ActiveProfile?.Render(canvas, SKPoint.Empty);
|
ActiveProfile?.Render(canvas, SKPointI.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
ProfileRendered(deltaTime, canvas, canvasInfo);
|
ProfileRendered(deltaTime, canvas, canvasInfo);
|
||||||
|
|||||||
@ -107,7 +107,7 @@ namespace Artemis.Core
|
|||||||
/// <returns>If found, the instance of the feature</returns>
|
/// <returns>If found, the instance of the feature</returns>
|
||||||
public T? GetFeature<T>() where T : PluginFeature
|
public T? GetFeature<T>() where T : PluginFeature
|
||||||
{
|
{
|
||||||
return _features.FirstOrDefault(i => i.Instance is T) as T;
|
return _features.FirstOrDefault(i => i.Instance is T)?.Instance as T;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -164,6 +164,11 @@ namespace Artemis.Core
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal bool HasEnabledFeatures()
|
||||||
|
{
|
||||||
|
return Entity.Features.Any(f => f.IsEnabled) || Features.Any(f => f.AlwaysEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
#region IDisposable
|
#region IDisposable
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@ -23,5 +23,10 @@ namespace Artemis.Core
|
|||||||
/// available icons
|
/// available icons
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string? Icon { get; set; }
|
public string? Icon { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marks the feature to always be enabled as long as the plugin is enabled
|
||||||
|
/// </summary>
|
||||||
|
public bool AlwaysEnabled { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -28,6 +28,7 @@ namespace Artemis.Core
|
|||||||
Name = attribute?.Name ?? featureType.Name.Humanize(LetterCasing.Title);
|
Name = attribute?.Name ?? featureType.Name.Humanize(LetterCasing.Title);
|
||||||
Description = attribute?.Description;
|
Description = attribute?.Description;
|
||||||
Icon = attribute?.Icon;
|
Icon = attribute?.Icon;
|
||||||
|
AlwaysEnabled = attribute?.AlwaysEnabled ?? false;
|
||||||
|
|
||||||
if (Icon != null) return;
|
if (Icon != null) return;
|
||||||
if (typeof(BaseDataModelExpansion).IsAssignableFrom(featureType))
|
if (typeof(BaseDataModelExpansion).IsAssignableFrom(featureType))
|
||||||
@ -55,6 +56,7 @@ namespace Artemis.Core
|
|||||||
Name = attribute?.Name ?? instance.GetType().Name.Humanize(LetterCasing.Title);
|
Name = attribute?.Name ?? instance.GetType().Name.Humanize(LetterCasing.Title);
|
||||||
Description = attribute?.Description;
|
Description = attribute?.Description;
|
||||||
Icon = attribute?.Icon;
|
Icon = attribute?.Icon;
|
||||||
|
AlwaysEnabled = attribute?.AlwaysEnabled ?? false;
|
||||||
Instance = instance;
|
Instance = instance;
|
||||||
|
|
||||||
if (Icon != null) return;
|
if (Icon != null) return;
|
||||||
@ -111,6 +113,12 @@ namespace Artemis.Core
|
|||||||
set => SetAndNotify(ref _icon, value);
|
set => SetAndNotify(ref _icon, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Marks the feature to always be enabled as long as the plugin is enabled and cannot be disabled
|
||||||
|
/// </summary>
|
||||||
|
[JsonProperty]
|
||||||
|
public bool AlwaysEnabled { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the feature this info is associated with
|
/// Gets the feature this info is associated with
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Buffers;
|
||||||
using System.Runtime.InteropServices;
|
using System.Runtime.InteropServices;
|
||||||
using Artemis.Core.SkiaSharp;
|
using Artemis.Core.SkiaSharp;
|
||||||
using RGB.NET.Core;
|
using RGB.NET.Core;
|
||||||
@ -12,25 +13,54 @@ namespace Artemis.Core
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public sealed class SKTexture : PixelTexture<byte>, IDisposable
|
public sealed class SKTexture : PixelTexture<byte>, IDisposable
|
||||||
{
|
{
|
||||||
|
private readonly bool _isScaledDown;
|
||||||
private readonly SKPixmap _pixelData;
|
private readonly SKPixmap _pixelData;
|
||||||
private readonly IntPtr _pixelDataPtr;
|
private readonly IntPtr _pixelDataPtr;
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
internal SKTexture(IManagedGraphicsContext? graphicsContext, int width, int height, float scale) : base(width, height, 4, new AverageByteSampler())
|
internal SKTexture(IManagedGraphicsContext? graphicsContext, int width, int height, float scale) : base(width, height, DATA_PER_PIXEL, new AverageByteSampler())
|
||||||
{
|
{
|
||||||
ImageInfo = new SKImageInfo(width, height);
|
ImageInfo = new SKImageInfo(width, height);
|
||||||
Surface = graphicsContext == null
|
Surface = graphicsContext == null
|
||||||
? SKSurface.Create(ImageInfo)
|
? SKSurface.Create(ImageInfo)
|
||||||
: SKSurface.Create(graphicsContext.GraphicsContext, true, ImageInfo);
|
: SKSurface.Create(graphicsContext.GraphicsContext, true, ImageInfo);
|
||||||
RenderScale = scale;
|
RenderScale = scale;
|
||||||
|
_isScaledDown = Math.Abs(scale - 1) > 0.001;
|
||||||
_pixelDataPtr = Marshal.AllocHGlobal(ImageInfo.BytesSize);
|
_pixelDataPtr = Marshal.AllocHGlobal(ImageInfo.BytesSize);
|
||||||
_pixelData = new SKPixmap(ImageInfo, _pixelDataPtr, ImageInfo.RowBytes);
|
_pixelData = new SKPixmap(ImageInfo, _pixelDataPtr, ImageInfo.RowBytes);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
private void ReleaseUnmanagedResources()
|
||||||
|
{
|
||||||
|
Marshal.FreeHGlobal(_pixelDataPtr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
~SKTexture()
|
||||||
|
{
|
||||||
|
ReleaseUnmanagedResources();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
Surface.Dispose();
|
||||||
|
_pixelData.Dispose();
|
||||||
|
|
||||||
|
ReleaseUnmanagedResources();
|
||||||
|
GC.SuppressFinalize(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
#region Constants
|
||||||
|
|
||||||
|
private const int STACK_ALLOC_LIMIT = 1024;
|
||||||
|
private const int DATA_PER_PIXEL = 4;
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
#region Methods
|
#region Methods
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -53,6 +83,61 @@ namespace Artemis.Core
|
|||||||
return new(pixel[2], pixel[1], pixel[0]);
|
return new(pixel[2], pixel[1], pixel[0]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public override Color this[in Rectangle rectangle]
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (Data.Length == 0) return Color.Transparent;
|
||||||
|
|
||||||
|
SKRectI skRectI = CreatedFlooredRectI(
|
||||||
|
Size.Width * rectangle.Location.X.Clamp(0, 1),
|
||||||
|
Size.Height * rectangle.Location.Y.Clamp(0, 1),
|
||||||
|
Size.Width * rectangle.Size.Width.Clamp(0, 1),
|
||||||
|
Size.Height * rectangle.Size.Height.Clamp(0, 1)
|
||||||
|
);
|
||||||
|
|
||||||
|
if (skRectI.Width == 0 || skRectI.Height == 0) return Color.Transparent;
|
||||||
|
if (skRectI.Width == 1 && skRectI.Height == 1) return GetColor(GetPixelData(skRectI.Left, skRectI.Top));
|
||||||
|
|
||||||
|
int bufferSize = skRectI.Width * skRectI.Height * DATA_PER_PIXEL;
|
||||||
|
if (bufferSize <= STACK_ALLOC_LIMIT)
|
||||||
|
{
|
||||||
|
Span<byte> buffer = stackalloc byte[bufferSize];
|
||||||
|
GetRegionData(skRectI.Left, skRectI.Top, skRectI.Width, skRectI.Height, buffer);
|
||||||
|
|
||||||
|
Span<byte> pixelData = stackalloc byte[DATA_PER_PIXEL];
|
||||||
|
Sampler.SampleColor(new SamplerInfo<byte>(skRectI.Width, skRectI.Height, buffer), pixelData);
|
||||||
|
|
||||||
|
return GetColor(pixelData);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
byte[] rent = ArrayPool<byte>.Shared.Rent(bufferSize);
|
||||||
|
|
||||||
|
Span<byte> buffer = new Span<byte>(rent).Slice(0, bufferSize);
|
||||||
|
GetRegionData(skRectI.Left, skRectI.Top, skRectI.Width, skRectI.Height, buffer);
|
||||||
|
|
||||||
|
Span<byte> pixelData = stackalloc byte[DATA_PER_PIXEL];
|
||||||
|
Sampler.SampleColor(new SamplerInfo<byte>(skRectI.Width, skRectI.Height, buffer), pixelData);
|
||||||
|
|
||||||
|
ArrayPool<byte>.Shared.Return(rent);
|
||||||
|
|
||||||
|
return GetColor(pixelData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static SKRectI CreatedFlooredRectI(float x, float y, float width, float height)
|
||||||
|
{
|
||||||
|
return new(
|
||||||
|
width <= 0.0 ? checked((int) Math.Floor(x)) : checked((int) Math.Ceiling(x)),
|
||||||
|
height <= 0.0 ? checked((int) Math.Floor(y)) : checked((int) Math.Ceiling(y)),
|
||||||
|
width >= 0.0 ? checked((int) Math.Floor(x + width)) : checked((int) Math.Ceiling(x + width)),
|
||||||
|
height >= 0.0 ? checked((int) Math.Floor(y + height)) : checked((int) Math.Ceiling(y + height))
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Properties & Fields
|
#region Properties & Fields
|
||||||
@ -84,30 +169,5 @@ namespace Artemis.Core
|
|||||||
public bool IsInvalid { get; private set; }
|
public bool IsInvalid { get; private set; }
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region IDisposable
|
|
||||||
|
|
||||||
private void ReleaseUnmanagedResources()
|
|
||||||
{
|
|
||||||
Marshal.FreeHGlobal(_pixelDataPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
public void Dispose()
|
|
||||||
{
|
|
||||||
Surface.Dispose();
|
|
||||||
_pixelData.Dispose();
|
|
||||||
|
|
||||||
ReleaseUnmanagedResources();
|
|
||||||
GC.SuppressFinalize(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
~SKTexture()
|
|
||||||
{
|
|
||||||
ReleaseUnmanagedResources();
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -144,7 +144,8 @@ namespace Artemis.Core.Services
|
|||||||
|
|
||||||
SKCanvas canvas = texture.Surface.Canvas;
|
SKCanvas canvas = texture.Surface.Canvas;
|
||||||
canvas.Save();
|
canvas.Save();
|
||||||
canvas.Scale(texture.RenderScale);
|
if (Math.Abs(texture.RenderScale - 1) > 0.001)
|
||||||
|
canvas.Scale(texture.RenderScale);
|
||||||
canvas.Clear(new SKColor(0, 0, 0));
|
canvas.Clear(new SKColor(0, 0, 0));
|
||||||
|
|
||||||
// While non-activated modules may be updated above if they expand the main data model, they may never render
|
// While non-activated modules may be updated above if they expand the main data model, they may never render
|
||||||
|
|||||||
@ -207,7 +207,7 @@ namespace Artemis.Core.Services
|
|||||||
// ReSharper disable InconsistentlySynchronizedField - It's read-only, idc
|
// ReSharper disable InconsistentlySynchronizedField - It's read-only, idc
|
||||||
_logger.Debug("Loaded {count} plugin(s)", _plugins.Count);
|
_logger.Debug("Loaded {count} plugin(s)", _plugins.Count);
|
||||||
|
|
||||||
bool adminRequired = _plugins.Any(p => p.Info.RequiresAdmin && p.Entity.IsEnabled && p.Entity.Features.Any(f => f.IsEnabled));
|
bool adminRequired = _plugins.Any(p => p.Info.RequiresAdmin && p.Entity.IsEnabled && p.HasEnabledFeatures());
|
||||||
if (!isElevated && adminRequired)
|
if (!isElevated && adminRequired)
|
||||||
{
|
{
|
||||||
_logger.Information("Restarting because one or more plugins requires elevation");
|
_logger.Information("Restarting because one or more plugins requires elevation");
|
||||||
@ -340,7 +340,7 @@ namespace Artemis.Core.Services
|
|||||||
if (plugin.Assembly == null)
|
if (plugin.Assembly == null)
|
||||||
throw new ArtemisPluginException(plugin, "Cannot enable a plugin that hasn't successfully been loaded");
|
throw new ArtemisPluginException(plugin, "Cannot enable a plugin that hasn't successfully been loaded");
|
||||||
|
|
||||||
if (plugin.Info.RequiresAdmin && plugin.Entity.Features.Any(f => f.IsEnabled) && !_isElevated)
|
if (plugin.Info.RequiresAdmin && plugin.HasEnabledFeatures() && !_isElevated)
|
||||||
{
|
{
|
||||||
if (!saveState)
|
if (!saveState)
|
||||||
throw new ArtemisCoreException("Cannot enable a plugin that requires elevation without saving it's state.");
|
throw new ArtemisCoreException("Cannot enable a plugin that requires elevation without saving it's state.");
|
||||||
@ -387,7 +387,7 @@ namespace Artemis.Core.Services
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Activate features after they are all loaded
|
// Activate features after they are all loaded
|
||||||
foreach (PluginFeatureInfo pluginFeature in plugin.Features.Where(f => f.Instance != null && f.Instance.Entity.IsEnabled))
|
foreach (PluginFeatureInfo pluginFeature in plugin.Features.Where(f => f.Instance != null && (f.Instance.Entity.IsEnabled || f.AlwaysEnabled)))
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@ -258,9 +258,17 @@ namespace Artemis.Core.Services
|
|||||||
else
|
else
|
||||||
_logger.Debug("Creating SKTexture with software-based graphics context");
|
_logger.Debug("Creating SKTexture with software-based graphics context");
|
||||||
|
|
||||||
|
float evenWidth = Surface.Boundary.Size.Width;
|
||||||
|
if (evenWidth % 2 != 0)
|
||||||
|
evenWidth++;
|
||||||
|
float evenHeight = Surface.Boundary.Size.Height;
|
||||||
|
if (evenHeight % 2 != 0)
|
||||||
|
evenHeight++;
|
||||||
|
|
||||||
float renderScale = (float) _renderScaleSetting.Value;
|
float renderScale = (float) _renderScaleSetting.Value;
|
||||||
int width = Math.Max(1, MathF.Min(Surface.Boundary.Size.Width * renderScale, 4096).RoundToInt());
|
int width = Math.Max(1, MathF.Min(evenWidth * renderScale, 4096).RoundToInt());
|
||||||
int height = Math.Max(1, MathF.Min(Surface.Boundary.Size.Height * renderScale, 4096).RoundToInt());
|
int height = Math.Max(1, MathF.Min(evenHeight * renderScale, 4096).RoundToInt());
|
||||||
|
|
||||||
_texture?.Dispose();
|
_texture?.Dispose();
|
||||||
_texture = new SKTexture(graphicsContext, width, height, renderScale);
|
_texture = new SKTexture(graphicsContext, width, height, renderScale);
|
||||||
_textureBrush.Texture = _texture;
|
_textureBrush.Texture = _texture;
|
||||||
|
|||||||
@ -30,7 +30,7 @@ namespace Artemis.Core
|
|||||||
public void Render(double deltaTime, SKCanvas canvas)
|
public void Render(double deltaTime, SKCanvas canvas)
|
||||||
{
|
{
|
||||||
AnimationProfile.Update(deltaTime);
|
AnimationProfile.Update(deltaTime);
|
||||||
AnimationProfile.Render(canvas, SKPoint.Empty);
|
AnimationProfile.Render(canvas, SKPointI.Empty);
|
||||||
}
|
}
|
||||||
|
|
||||||
private Profile CreateIntroProfile()
|
private Profile CreateIntroProfile()
|
||||||
|
|||||||
@ -6,9 +6,11 @@ using System.Linq;
|
|||||||
using System.Timers;
|
using System.Timers;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using System.Windows.Input;
|
||||||
using System.Windows.Media;
|
using System.Windows.Media;
|
||||||
using System.Windows.Media.Imaging;
|
using System.Windows.Media.Imaging;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
|
using SkiaSharp;
|
||||||
using Stylet;
|
using Stylet;
|
||||||
|
|
||||||
namespace Artemis.UI.Shared
|
namespace Artemis.UI.Shared
|
||||||
@ -54,6 +56,7 @@ namespace Artemis.UI.Shared
|
|||||||
_timer = new Timer(40);
|
_timer = new Timer(40);
|
||||||
_timer.Elapsed += TimerOnTick;
|
_timer.Elapsed += TimerOnTick;
|
||||||
|
|
||||||
|
MouseLeftButtonUp += OnMouseLeftButtonUp;
|
||||||
Loaded += OnLoaded;
|
Loaded += OnLoaded;
|
||||||
Unloaded += OnUnloaded;
|
Unloaded += OnUnloaded;
|
||||||
}
|
}
|
||||||
@ -85,18 +88,6 @@ namespace Artemis.UI.Shared
|
|||||||
set => SetValue(HighlightedLedsProperty, value);
|
set => SetValue(HighlightedLedsProperty, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="disposing">
|
|
||||||
/// <see langword="true" /> to release both managed and unmanaged resources;
|
|
||||||
/// <see langword="false" /> to release only unmanaged resources.
|
|
||||||
/// </param>
|
|
||||||
protected virtual void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing) _timer.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void OnRender(DrawingContext drawingContext)
|
protected override void OnRender(DrawingContext drawingContext)
|
||||||
{
|
{
|
||||||
@ -149,6 +140,7 @@ namespace Artemis.UI.Shared
|
|||||||
return ResizeKeepAspect(deviceSize, availableSize.Width, availableSize.Height);
|
return ResizeKeepAspect(deviceSize, availableSize.Width, availableSize.Height);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private static Size ResizeKeepAspect(Size src, double maxWidth, double maxHeight)
|
private static Size ResizeKeepAspect(Size src, double maxWidth, double maxHeight)
|
||||||
{
|
{
|
||||||
double scale;
|
double scale;
|
||||||
@ -191,6 +183,21 @@ namespace Artemis.UI.Shared
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void OnMouseLeftButtonUp(object sender, MouseButtonEventArgs e)
|
||||||
|
{
|
||||||
|
if (Device == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Point position = e.GetPosition(this);
|
||||||
|
double x = (position.X / RenderSize.Width);
|
||||||
|
double y = (position.Y / RenderSize.Height);
|
||||||
|
|
||||||
|
Point scaledPosition = new(x * Device.Rectangle.Width, y * Device.Rectangle.Height);
|
||||||
|
DeviceVisualizerLed? deviceVisualizerLed = _deviceVisualizerLeds.FirstOrDefault(l => l.DisplayGeometry != null && l.LedRect.Contains(scaledPosition));
|
||||||
|
if (deviceVisualizerLed != null)
|
||||||
|
OnLedClicked(new LedClickedEventArgs(deviceVisualizerLed.Led.Device, deviceVisualizerLed.Led));
|
||||||
|
}
|
||||||
|
|
||||||
private void OnLoaded(object? sender, RoutedEventArgs e)
|
private void OnLoaded(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
_timer.Start();
|
_timer.Start();
|
||||||
@ -310,11 +317,43 @@ namespace Artemis.UI.Shared
|
|||||||
drawingContext.Close();
|
drawingContext.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
public event EventHandler<LedClickedEventArgs>? LedClicked;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the <see cref="LedClicked" /> event
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="e"></param>
|
||||||
|
protected virtual void OnLedClicked(LedClickedEventArgs e)
|
||||||
|
{
|
||||||
|
LedClicked?.Invoke(this, e);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region IDisposable
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Releases the unmanaged resources used by the object and optionally releases the managed resources.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="disposing">
|
||||||
|
/// <see langword="true" /> to release both managed and unmanaged resources;
|
||||||
|
/// <see langword="false" /> to release only unmanaged resources.
|
||||||
|
/// </param>
|
||||||
|
protected virtual void Dispose(bool disposing)
|
||||||
|
{
|
||||||
|
if (disposing) _timer.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void Dispose()
|
public void Dispose()
|
||||||
{
|
{
|
||||||
Dispose(true);
|
Dispose(true);
|
||||||
GC.SuppressFinalize(this);
|
GC.SuppressFinalize(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
27
src/Artemis.UI.Shared/Events/LedClickedEventArgs.cs
Normal file
27
src/Artemis.UI.Shared/Events/LedClickedEventArgs.cs
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
using System;
|
||||||
|
using Artemis.Core;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Shared
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Provides data on LED click events raised by the device visualizer
|
||||||
|
/// </summary>
|
||||||
|
public class LedClickedEventArgs : EventArgs
|
||||||
|
{
|
||||||
|
internal LedClickedEventArgs(ArtemisDevice device, ArtemisLed led)
|
||||||
|
{
|
||||||
|
Device = device;
|
||||||
|
Led = led;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The device that was clicked
|
||||||
|
/// </summary>
|
||||||
|
public ArtemisDevice Device { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The LED that was clicked
|
||||||
|
/// </summary>
|
||||||
|
public ArtemisLed Led { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -11,6 +11,7 @@ using Artemis.UI.Shared.Services.Models;
|
|||||||
using Ninject;
|
using Ninject;
|
||||||
using Ninject.Parameters;
|
using Ninject.Parameters;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
using SkiaSharp;
|
||||||
using SkiaSharp.Views.WPF;
|
using SkiaSharp.Views.WPF;
|
||||||
using Stylet;
|
using Stylet;
|
||||||
|
|
||||||
@ -350,7 +351,10 @@ namespace Artemis.UI.Shared.Services
|
|||||||
|
|
||||||
public List<ArtemisLed> GetLedsInRectangle(Rect rect)
|
public List<ArtemisLed> GetLedsInRectangle(Rect rect)
|
||||||
{
|
{
|
||||||
return _rgbService.EnabledDevices.SelectMany(d => d.Leds).Where(led => led.AbsoluteRectangle.IntersectsWith(rect.ToSKRect())).ToList();
|
return _rgbService.EnabledDevices
|
||||||
|
.SelectMany(d => d.Leds)
|
||||||
|
.Where(led => led.AbsoluteRectangle.IntersectsWith(SKRectI.Round(rect.ToSKRect())))
|
||||||
|
.ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
#region Copy/paste
|
#region Copy/paste
|
||||||
|
|||||||
@ -6,6 +6,7 @@
|
|||||||
xmlns:s="https://github.com/canton7/Stylet"
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
|
xmlns:propertyInput="clr-namespace:Artemis.UI.DefaultTypes.PropertyInput"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800"
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
d:DataContext="{d:DesignInstance propertyInput:FloatPropertyInputViewModel}">
|
d:DataContext="{d:DesignInstance propertyInput:FloatPropertyInputViewModel}">
|
||||||
|
|||||||
@ -154,7 +154,7 @@
|
|||||||
</materialDesign:ToggleButtonAssist.OnContent>
|
</materialDesign:ToggleButtonAssist.OnContent>
|
||||||
</ToggleButton>
|
</ToggleButton>
|
||||||
|
|
||||||
<ItemsControl Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="3" ItemsSource="{Binding Items, IsAsync=True}" Margin="0 3 0 0">
|
<ItemsControl Grid.Row="1" Grid.Column="1" Grid.ColumnSpan="3" ItemsSource="{Binding Items}" Margin="0 3 0 0">
|
||||||
<ItemsControl.ItemTemplate>
|
<ItemsControl.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
|
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.UI.Extensions;
|
using Artemis.UI.Extensions;
|
||||||
using Artemis.UI.Ninject.Factories;
|
using Artemis.UI.Ninject.Factories;
|
||||||
@ -16,7 +16,6 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
|||||||
private readonly IDataModelConditionsVmFactory _dataModelConditionsVmFactory;
|
private readonly IDataModelConditionsVmFactory _dataModelConditionsVmFactory;
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private bool _isEventGroup;
|
private bool _isEventGroup;
|
||||||
private bool _isInitialized;
|
|
||||||
private bool _isRootGroup;
|
private bool _isRootGroup;
|
||||||
|
|
||||||
public DataModelConditionGroupViewModel(DataModelConditionGroup dataModelConditionGroup,
|
public DataModelConditionGroupViewModel(DataModelConditionGroup dataModelConditionGroup,
|
||||||
@ -30,12 +29,6 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
|||||||
_dataModelConditionsVmFactory = dataModelConditionsVmFactory;
|
_dataModelConditionsVmFactory = dataModelConditionsVmFactory;
|
||||||
|
|
||||||
Items.CollectionChanged += (_, _) => NotifyOfPropertyChange(nameof(DisplayBooleanOperator));
|
Items.CollectionChanged += (_, _) => NotifyOfPropertyChange(nameof(DisplayBooleanOperator));
|
||||||
|
|
||||||
Execute.PostToUIThread(async () =>
|
|
||||||
{
|
|
||||||
await Task.Delay(50);
|
|
||||||
IsInitialized = true;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ConditionGroupType GroupType { get; }
|
public ConditionGroupType GroupType { get; }
|
||||||
@ -63,12 +56,6 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsInitialized
|
|
||||||
{
|
|
||||||
get => _isInitialized;
|
|
||||||
set => SetAndNotify(ref _isInitialized, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DisplayBooleanOperator => Items.Count > 1;
|
public bool DisplayBooleanOperator => Items.Count > 1;
|
||||||
public bool DisplayEvaluationResult => GroupType == ConditionGroupType.General && !IsEventGroup;
|
public bool DisplayEvaluationResult => GroupType == ConditionGroupType.General && !IsEventGroup;
|
||||||
public string SelectedBooleanOperator => DataModelConditionGroup.BooleanOperator.Humanize();
|
public string SelectedBooleanOperator => DataModelConditionGroup.BooleanOperator.Humanize();
|
||||||
@ -132,7 +119,9 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
|||||||
{
|
{
|
||||||
NotifyOfPropertyChange(nameof(SelectedBooleanOperator));
|
NotifyOfPropertyChange(nameof(SelectedBooleanOperator));
|
||||||
// Remove VMs of effects no longer applied on the layer
|
// Remove VMs of effects no longer applied on the layer
|
||||||
Items.RemoveRange(Items.Where(c => !DataModelConditionGroup.Children.Contains(c.Model)).ToList());
|
List<DataModelConditionViewModel> toRemove = Items.Where(c => !DataModelConditionGroup.Children.Contains(c.Model)).ToList();
|
||||||
|
if (toRemove.Any())
|
||||||
|
Items.RemoveRange(toRemove);
|
||||||
|
|
||||||
foreach (DataModelConditionPart childModel in Model.Children)
|
foreach (DataModelConditionPart childModel in Model.Children)
|
||||||
{
|
{
|
||||||
@ -169,8 +158,10 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
|
|||||||
|
|
||||||
IsEventGroup = Items.Any(i => i is DataModelConditionEventViewModel);
|
IsEventGroup = Items.Any(i => i is DataModelConditionEventViewModel);
|
||||||
if (IsEventGroup)
|
if (IsEventGroup)
|
||||||
|
{
|
||||||
if (DataModelConditionGroup.BooleanOperator != BooleanOperator.And)
|
if (DataModelConditionGroup.BooleanOperator != BooleanOperator.And)
|
||||||
SelectBooleanOperator("And");
|
SelectBooleanOperator("And");
|
||||||
|
}
|
||||||
|
|
||||||
OnUpdated();
|
OnUpdated();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -42,12 +42,12 @@
|
|||||||
Margin="-10 0 -10 -5">
|
Margin="-10 0 -10 -5">
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
|
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False"/>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListBox.ItemTemplate>
|
</ListBox.ItemTemplate>
|
||||||
<ListBox.ItemsPanel>
|
<ListBox.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
<VirtualizingStackPanel />
|
<VirtualizingStackPanel/>
|
||||||
</ItemsPanelTemplate>
|
</ItemsPanelTemplate>
|
||||||
</ListBox.ItemsPanel>
|
</ListBox.ItemsPanel>
|
||||||
</ListBox>
|
</ListBox>
|
||||||
|
|||||||
@ -44,6 +44,11 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.Conditio
|
|||||||
_profileEditorService.UpdateSelectedProfileElement();
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void RemoveCondition(DataBindingCondition<TLayerProperty, TProperty> dataBindingCondition)
|
||||||
|
{
|
||||||
|
ConditionalDataBinding.RemoveCondition(dataBindingCondition);
|
||||||
|
}
|
||||||
|
|
||||||
protected override void OnInitialActivate()
|
protected override void OnInitialActivate()
|
||||||
{
|
{
|
||||||
Initialize();
|
Initialize();
|
||||||
|
|||||||
@ -4,24 +4,63 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:s="https://github.com/canton7/Stylet"
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800">
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
<Grid>
|
<Border BorderThickness="0 0 0 1"
|
||||||
<Grid.RowDefinitions>
|
BorderBrush="{DynamicResource MaterialDesignDivider}"
|
||||||
<RowDefinition Height="Auto" />
|
Margin="0 0 0 -4"
|
||||||
<RowDefinition Height="Auto" />
|
Padding="0 4"
|
||||||
</Grid.RowDefinitions>
|
Background="Transparent">
|
||||||
<ContentControl Grid.Row="0"
|
<Border.ContextMenu>
|
||||||
s:View.Model="{Binding ActiveItem}"
|
<ContextMenu>
|
||||||
VerticalContentAlignment="Stretch"
|
<MenuItem Header="Add new condition" Command="{s:Action AddCondition}">
|
||||||
HorizontalContentAlignment="Stretch"
|
<MenuItem.Icon>
|
||||||
IsTabStop="False" />
|
<materialDesign:PackIcon Kind="CodeNotEqual" />
|
||||||
|
</MenuItem.Icon>
|
||||||
|
</MenuItem>
|
||||||
|
<Separator />
|
||||||
|
<MenuItem Header="Duplicate" Command="{s:Action DuplicateCondition}" InputGestureText="Ctrl+D" IsEnabled="False">
|
||||||
|
<MenuItem.Icon>
|
||||||
|
<materialDesign:PackIcon Kind="ContentDuplicate" />
|
||||||
|
</MenuItem.Icon>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem Header="Copy" Command="{s:Action CopyCondition}" InputGestureText="Ctrl+C" IsEnabled="False">
|
||||||
|
<MenuItem.Icon>
|
||||||
|
<materialDesign:PackIcon Kind="ContentCopy" />
|
||||||
|
</MenuItem.Icon>
|
||||||
|
</MenuItem>
|
||||||
|
<MenuItem Header="Paste" Command="{s:Action PasteCondition}" InputGestureText="Ctrl+V" IsEnabled="False">
|
||||||
|
<MenuItem.Icon>
|
||||||
|
<materialDesign:PackIcon Kind="ContentPaste" />
|
||||||
|
</MenuItem.Icon>
|
||||||
|
</MenuItem>
|
||||||
|
<Separator />
|
||||||
|
<MenuItem Header="Delete" Command="{s:Action RemoveCondition}" InputGestureText="Del">
|
||||||
|
<MenuItem.Icon>
|
||||||
|
<materialDesign:PackIcon Kind="TrashCan" />
|
||||||
|
</MenuItem.Icon>
|
||||||
|
</MenuItem>
|
||||||
|
</ContextMenu>
|
||||||
|
</Border.ContextMenu>
|
||||||
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<ContentControl Grid.Row="0"
|
||||||
|
s:View.Model="{Binding ActiveItem}"
|
||||||
|
VerticalContentAlignment="Stretch"
|
||||||
|
HorizontalContentAlignment="Stretch"
|
||||||
|
IsTabStop="False"
|
||||||
|
Margin="0 -10 0 0"/>
|
||||||
|
|
||||||
<ContentControl Grid.Row="1"
|
<ContentControl Grid.Row="1"
|
||||||
Margin="26 2 0 0"
|
Margin="26 0 0 0"
|
||||||
s:View.Model="{Binding ValueViewModel}"
|
s:View.Model="{Binding ValueViewModel}"
|
||||||
VerticalContentAlignment="Stretch"
|
VerticalContentAlignment="Stretch"
|
||||||
HorizontalContentAlignment="Stretch"
|
HorizontalContentAlignment="Stretch"
|
||||||
IsTabStop="False" />
|
IsTabStop="False" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
</Border>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -61,6 +61,17 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.Conditio
|
|||||||
ActiveItem?.Evaluate();
|
ActiveItem?.Evaluate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AddCondition()
|
||||||
|
{
|
||||||
|
((ConditionalDataBindingModeViewModel<TLayerProperty, TProperty>) Parent).AddCondition();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveCondition()
|
||||||
|
{
|
||||||
|
((ConditionalDataBindingModeViewModel<TLayerProperty, TProperty>)Parent).RemoveCondition(DataBindingCondition);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
#region IDisposable
|
#region IDisposable
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="0.75*" />
|
<ColumnDefinition Width="0.50*" />
|
||||||
<ColumnDefinition Width="*" />
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
@ -33,6 +33,7 @@
|
|||||||
<RowDefinition Height="48" />
|
<RowDefinition Height="48" />
|
||||||
<RowDefinition Height="48" />
|
<RowDefinition Height="48" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<ComboBox Grid.Row="0"
|
<ComboBox Grid.Row="0"
|
||||||
@ -93,7 +94,7 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<TextBlock Grid.Row="0" Margin="10 10 0 0">
|
<TextBlock Grid.Row="0" Margin="10 10 0 0">
|
||||||
Data binding result
|
Result
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
<TextBlock Grid.Row="0"
|
<TextBlock Grid.Row="0"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
@ -101,7 +102,7 @@
|
|||||||
Visibility="{Binding AlwaysApplyDataBindings.Value, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}}"
|
Visibility="{Binding AlwaysApplyDataBindings.Value, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}}"
|
||||||
ToolTip="Check 'Apply data bindings in editor'"
|
ToolTip="Check 'Apply data bindings in editor'"
|
||||||
Cursor="Help">
|
Cursor="Help">
|
||||||
Other data bindings not updating?
|
Other bindings not updating?
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
<Separator Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Style="{StaticResource MaterialDesignLightSeparator}" Margin="0" />
|
<Separator Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Style="{StaticResource MaterialDesignLightSeparator}" Margin="0" />
|
||||||
<Grid Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Margin="10 4 10 10">
|
<Grid Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2" Margin="10 4 10 10">
|
||||||
@ -134,12 +135,39 @@
|
|||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</materialDesign:Card>
|
</materialDesign:Card>
|
||||||
|
|
||||||
|
<Grid Grid.Row="4" VerticalAlignment="Bottom" Margin="0 5">
|
||||||
|
<Grid.ColumnDefinitions>
|
||||||
|
<ColumnDefinition />
|
||||||
|
<ColumnDefinition />
|
||||||
|
</Grid.ColumnDefinitions>
|
||||||
|
<Button Grid.Column="0"
|
||||||
|
Style="{StaticResource MaterialDesignRaisedDarkButton}"
|
||||||
|
Margin="0 0 5 0"
|
||||||
|
ToolTip="Copy the entire data binding"
|
||||||
|
Command="{s:Action CopyDataBinding}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<materialDesign:PackIcon Kind="ContentCopy" />
|
||||||
|
<TextBlock Text="COPY" Margin="8 0 0 0" />
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
<Button Grid.Column="1"
|
||||||
|
Style="{StaticResource MaterialDesignRaisedDarkButton}"
|
||||||
|
Margin="5 0 0 0"
|
||||||
|
ToolTip="Paste the entire data binding"
|
||||||
|
Command="{s:Action PasteDataBinding}">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<materialDesign:PackIcon Kind="ContentPaste" />
|
||||||
|
<TextBlock Text="PASTE" Margin="8 0 0 0" />
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
</materialDesign:Card>
|
</materialDesign:Card>
|
||||||
|
|
||||||
<materialDesign:Card Grid.Column="1" UniformCornerRadius="0" Background="{DynamicResource MaterialDesignToolBarBackground}" Panel.ZIndex="1">
|
<materialDesign:Card Grid.Column="1" UniformCornerRadius="0" Background="{DynamicResource MaterialDesignToolBarBackground}" Panel.ZIndex="1">
|
||||||
<Grid Margin="10 5">
|
<Grid Margin="10 5">
|
||||||
<ContentControl s:View.Model="{Binding ActiveItem, IsAsync=True}"
|
<ContentControl s:View.Model="{Binding ActiveItem}"
|
||||||
VerticalContentAlignment="Stretch"
|
VerticalContentAlignment="Stretch"
|
||||||
HorizontalContentAlignment="Stretch"
|
HorizontalContentAlignment="Stretch"
|
||||||
IsTabStop="False" />
|
IsTabStop="False" />
|
||||||
|
|||||||
@ -3,6 +3,8 @@ using System.Linq;
|
|||||||
using System.Timers;
|
using System.Timers;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.Storage.Entities.Profile.DataBindings;
|
||||||
|
using Artemis.UI.Exceptions;
|
||||||
using Artemis.UI.Ninject.Factories;
|
using Artemis.UI.Ninject.Factories;
|
||||||
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline;
|
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
@ -186,16 +188,15 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
if (Registration.DataBinding != null && SelectedDataBindingMode == DataBindingModeType.None)
|
if (Registration.DataBinding != null && SelectedDataBindingMode == DataBindingModeType.None)
|
||||||
{
|
|
||||||
RemoveDataBinding();
|
RemoveDataBinding();
|
||||||
CreateDataBindingModeModeViewModel();
|
else
|
||||||
return;
|
{
|
||||||
|
if (Registration.DataBinding == null && SelectedDataBindingMode != DataBindingModeType.None)
|
||||||
|
EnableDataBinding();
|
||||||
|
|
||||||
|
Registration.DataBinding!.ChangeDataBindingMode(SelectedDataBindingMode);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Registration.DataBinding == null && SelectedDataBindingMode != DataBindingModeType.None)
|
|
||||||
EnableDataBinding();
|
|
||||||
|
|
||||||
Registration.DataBinding.ChangeDataBindingMode(SelectedDataBindingMode);
|
|
||||||
CreateDataBindingModeModeViewModel();
|
CreateDataBindingModeModeViewModel();
|
||||||
_profileEditorService.UpdateSelectedProfileElement();
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
}
|
}
|
||||||
@ -250,12 +251,40 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
|
|||||||
if (Registration.DataBinding == null)
|
if (Registration.DataBinding == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
ActiveItem = null;
|
||||||
Registration.LayerProperty.DisableDataBinding(Registration.DataBinding);
|
Registration.LayerProperty.DisableDataBinding(Registration.DataBinding);
|
||||||
Update();
|
Update();
|
||||||
|
|
||||||
_profileEditorService.UpdateSelectedProfileElement();
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void CopyDataBinding()
|
||||||
|
{
|
||||||
|
if (Registration.DataBinding != null)
|
||||||
|
JsonClipboard.SetObject(Registration.DataBinding.Entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void PasteDataBinding()
|
||||||
|
{
|
||||||
|
if (Registration.DataBinding == null)
|
||||||
|
Registration.LayerProperty.EnableDataBinding(Registration);
|
||||||
|
if (Registration.DataBinding == null)
|
||||||
|
throw new ArtemisUIException("Failed to create a data binding in order to paste");
|
||||||
|
|
||||||
|
DataBindingEntity dataBindingEntity = JsonClipboard.GetData<DataBindingEntity>();
|
||||||
|
if (dataBindingEntity == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
Registration.DataBinding.EasingTime = dataBindingEntity.EasingTime;
|
||||||
|
Registration.DataBinding.EasingFunction = (Easings.Functions) dataBindingEntity.EasingFunction;
|
||||||
|
Registration.DataBinding.ApplyDataBindingEntity(dataBindingEntity.DataBindingMode);
|
||||||
|
CreateDataBindingModeModeViewModel();
|
||||||
|
Update();
|
||||||
|
|
||||||
|
|
||||||
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
|
}
|
||||||
|
|
||||||
private void OnFrameRendered(object sender, FrameRenderedEventArgs e)
|
private void OnFrameRendered(object sender, FrameRenderedEventArgs e)
|
||||||
{
|
{
|
||||||
UpdateTestResult();
|
UpdateTestResult();
|
||||||
|
|||||||
@ -8,7 +8,7 @@
|
|||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800">
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
<Grid Margin="5 10 0 0">
|
<Grid Margin="0 5 0 0">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition />
|
<ColumnDefinition />
|
||||||
<ColumnDefinition />
|
<ColumnDefinition />
|
||||||
@ -32,11 +32,7 @@
|
|||||||
Padding="6 4"
|
Padding="6 4"
|
||||||
Height="22"
|
Height="22"
|
||||||
Command="{s:Action AddModifier}">
|
Command="{s:Action AddModifier}">
|
||||||
<StackPanel Orientation="Horizontal">
|
ADD MODIFIER
|
||||||
<TextBlock>
|
|
||||||
ADD MODIFIER
|
|
||||||
</TextBlock>
|
|
||||||
</StackPanel>
|
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<ListBox Grid.Row="1"
|
<ListBox Grid.Row="1"
|
||||||
|
|||||||
@ -385,7 +385,8 @@
|
|||||||
Width="110"
|
Width="110"
|
||||||
ToolTip="Add a new segment to the timeline"
|
ToolTip="Add a new segment to the timeline"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
IsEnabled="{Binding SelectedProfileElement, Converter={StaticResource NullToBooleanConverter}}">
|
IsEnabled="{Binding SelectedProfileElement, Converter={StaticResource NullToBooleanConverter}}"
|
||||||
|
Visibility="{Binding TimelineVisible, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
|
||||||
<Button.Style>
|
<Button.Style>
|
||||||
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource MaterialDesignFlatMidBgButton}">
|
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource MaterialDesignFlatMidBgButton}">
|
||||||
<Style.Triggers>
|
<Style.Triggers>
|
||||||
|
|||||||
@ -134,12 +134,17 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
|||||||
public int RightSideIndex
|
public int RightSideIndex
|
||||||
{
|
{
|
||||||
get => _rightSideIndex;
|
get => _rightSideIndex;
|
||||||
set => SetAndNotify(ref _rightSideIndex, value);
|
set
|
||||||
|
{
|
||||||
|
if (!SetAndNotify(ref _rightSideIndex, value)) return;
|
||||||
|
NotifyOfPropertyChange(nameof(TimelineVisible));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanToggleEffectsViewModel => SelectedProfileElement != null && DateTime.Now - _lastEffectsViewModelToggle > TimeSpan.FromMilliseconds(250);
|
public bool CanToggleEffectsViewModel => SelectedProfileElement != null && DateTime.Now - _lastEffectsViewModelToggle > TimeSpan.FromMilliseconds(250);
|
||||||
|
|
||||||
public bool PropertyTreeVisible => PropertyTreeIndex == 0;
|
public bool PropertyTreeVisible => PropertyTreeIndex == 0;
|
||||||
|
public bool TimelineVisible => RightSideIndex == 0;
|
||||||
|
|
||||||
public RenderProfileElement SelectedProfileElement
|
public RenderProfileElement SelectedProfileElement
|
||||||
{
|
{
|
||||||
|
|||||||
@ -70,16 +70,10 @@
|
|||||||
ToolTip="{Binding LayerProperty.PropertyDescription.Description}"
|
ToolTip="{Binding LayerProperty.PropertyDescription.Description}"
|
||||||
HorizontalAlignment="Left" />
|
HorizontalAlignment="Left" />
|
||||||
|
|
||||||
<ContentControl Grid.Column="2" Margin="5 0" s:View.Model="{Binding PropertyInputViewModel, IsAsync=True}" ToolTip="{Binding LayerProperty.PropertyDescription.Description}">
|
<ContentControl Grid.Column="2"
|
||||||
<ContentControl.Resources>
|
Margin="5 0"
|
||||||
<Style TargetType="TextBlock">
|
s:View.Model="{Binding PropertyInputViewModel, IsAsync=True}"
|
||||||
<Setter Property="Margin" Value="0 0 5 4" />
|
ToolTip="{Binding LayerProperty.PropertyDescription.Description}"/>
|
||||||
<Setter Property="VerticalAlignment" Value="Bottom" />
|
|
||||||
<Setter Property="FontSize" Value="11" />
|
|
||||||
<Setter Property="FontWeight" Value="Light" />
|
|
||||||
</Style>
|
|
||||||
</ContentControl.Resources>
|
|
||||||
</ContentControl>
|
|
||||||
|
|
||||||
<Button Grid.Column="3"
|
<Button Grid.Column="3"
|
||||||
Command="{s:Action ResetToDefault}"
|
Command="{s:Action ResetToDefault}"
|
||||||
|
|||||||
@ -110,7 +110,7 @@
|
|||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
ShowColors="True"
|
ShowColors="True"
|
||||||
Margin="0 0 100 0" />
|
LedClicked="{s:Action OnLedClicked}"/>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<GridSplitter Grid.Column="1" Width="15" Margin="-15 0 0 0" Background="Transparent" HorizontalAlignment="Stretch" Panel.ZIndex="3" />
|
<GridSplitter Grid.Column="1" Width="15" Margin="-15 0 0 0" Background="Transparent" HorizontalAlignment="Stretch" Panel.ZIndex="3" />
|
||||||
|
|||||||
@ -8,6 +8,7 @@ using Artemis.Core;
|
|||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
using Artemis.UI.Ninject.Factories;
|
using Artemis.UI.Ninject.Factories;
|
||||||
using Artemis.UI.Screens.Shared;
|
using Artemis.UI.Screens.Shared;
|
||||||
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using MaterialDesignThemes.Wpf;
|
using MaterialDesignThemes.Wpf;
|
||||||
using Ookii.Dialogs.Wpf;
|
using Ookii.Dialogs.Wpf;
|
||||||
@ -197,6 +198,11 @@ namespace Artemis.UI.Screens.Settings.Device
|
|||||||
NotifyOfPropertyChange(nameof(CanExportLayout));
|
NotifyOfPropertyChange(nameof(CanExportLayout));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void OnLedClicked(object sender, LedClickedEventArgs e)
|
||||||
|
{
|
||||||
|
SelectedLed = e.Led;
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -151,8 +151,8 @@
|
|||||||
|
|
||||||
<mde:Autocomplete Style="{StaticResource MaterialDesignAutocomplete}"
|
<mde:Autocomplete Style="{StaticResource MaterialDesignAutocomplete}"
|
||||||
AutocompleteSource="{Binding Path=AutocompleteSource}"
|
AutocompleteSource="{Binding Path=AutocompleteSource}"
|
||||||
SearchOnInitialFocus="True"
|
|
||||||
SelectedItem="{Binding SelectedRegion, Mode=TwoWay}"
|
SelectedItem="{Binding SelectedRegion, Mode=TwoWay}"
|
||||||
|
SearchOnInitialFocus="True"
|
||||||
Hint="Select a logical layout"
|
Hint="Select a logical layout"
|
||||||
Margin="0,16,0,0"
|
Margin="0,16,0,0"
|
||||||
FontSize="15"
|
FontSize="15"
|
||||||
|
|||||||
@ -24,12 +24,7 @@ namespace Artemis.UI.Screens.Settings.Device
|
|||||||
Device = device;
|
Device = device;
|
||||||
SelectPhysicalLayout = !device.DeviceProvider.CanDetectPhysicalLayout;
|
SelectPhysicalLayout = !device.DeviceProvider.CanDetectPhysicalLayout;
|
||||||
|
|
||||||
Task.Run(() =>
|
Task.Run(() => AutocompleteSource = new RegionInfoAutocompleteSource());
|
||||||
{
|
|
||||||
AutocompleteSource = new RegionInfoAutocompleteSource();
|
|
||||||
SelectedRegion = AutocompleteSource.Regions.FirstOrDefault(r => r.TwoLetterISORegionName == Device.LogicalLayout ||
|
|
||||||
r.TwoLetterISORegionName == "US" && Device.LogicalLayout == "NA");
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArtemisDevice Device { get; }
|
public ArtemisDevice Device { get; }
|
||||||
|
|||||||
@ -59,9 +59,12 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
|
|||||||
|
|
||||||
LogLevels = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(LogEventLevel)));
|
LogLevels = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(LogEventLevel)));
|
||||||
ColorSchemes = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(ApplicationColorScheme)));
|
ColorSchemes = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(ApplicationColorScheme)));
|
||||||
RenderScales = new List<Tuple<string, double>> {new("10%", 0.1)};
|
RenderScales = new List<Tuple<string, double>>
|
||||||
for (int i = 25; i <= 100; i += 25)
|
{
|
||||||
RenderScales.Add(new Tuple<string, double>(i + "%", i / 100.0));
|
new("25%", 0.25),
|
||||||
|
new("50%", 0.5),
|
||||||
|
new("100%", 1),
|
||||||
|
};
|
||||||
|
|
||||||
TargetFrameRates = new List<Tuple<string, int>>();
|
TargetFrameRates = new List<Tuple<string, int>>();
|
||||||
for (int i = 10; i <= 30; i += 5)
|
for (int i = 10; i <= 30; i += 5)
|
||||||
|
|||||||
@ -50,13 +50,17 @@
|
|||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Margin="8"
|
Margin="8"
|
||||||
Visibility="{Binding Enabling, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay, FallbackValue=Collapsed}"
|
Visibility="{Binding Enabling, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay, FallbackValue=Collapsed}"
|
||||||
Orientation="Horizontal">
|
Orientation="Horizontal"
|
||||||
|
ToolTip="This feature cannot be disabled without disabling the whole plugin"
|
||||||
|
ToolTipService.IsEnabled="{Binding FeatureInfo.AlwaysEnabled}">
|
||||||
<materialDesign:PackIcon Kind="ShieldHalfFull"
|
<materialDesign:PackIcon Kind="ShieldHalfFull"
|
||||||
ToolTip="Plugin requires admin rights"
|
ToolTip="Plugin requires admin rights"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
Margin="0 0 5 0"
|
Margin="0 0 5 0"
|
||||||
Visibility="{Binding ShowShield, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
|
Visibility="{Binding ShowShield, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
|
||||||
<CheckBox Style="{StaticResource MaterialDesignCheckBox}" IsChecked="{Binding IsEnabled}" IsEnabled="{Binding FeatureInfo.Plugin.IsEnabled}">
|
<CheckBox Style="{StaticResource MaterialDesignCheckBox}"
|
||||||
|
IsChecked="{Binding IsEnabled}"
|
||||||
|
IsEnabled="{Binding CanToggleEnabled}">
|
||||||
Feature enabled
|
Feature enabled
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|||||||
@ -16,6 +16,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
|||||||
private readonly IPluginManagementService _pluginManagementService;
|
private readonly IPluginManagementService _pluginManagementService;
|
||||||
private bool _enabling;
|
private bool _enabling;
|
||||||
private readonly IMessageService _messageService;
|
private readonly IMessageService _messageService;
|
||||||
|
private bool _canToggleEnabled;
|
||||||
|
|
||||||
public PluginFeatureViewModel(PluginFeatureInfo pluginFeatureInfo,
|
public PluginFeatureViewModel(PluginFeatureInfo pluginFeatureInfo,
|
||||||
bool showShield,
|
bool showShield,
|
||||||
@ -50,6 +51,8 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
|||||||
set => Task.Run(() => UpdateEnabled(value));
|
set => Task.Run(() => UpdateEnabled(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool CanToggleEnabled => FeatureInfo.Plugin.IsEnabled && !FeatureInfo.AlwaysEnabled;
|
||||||
|
|
||||||
public void ShowLogsFolder()
|
public void ShowLogsFolder()
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
@ -76,6 +79,9 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
|||||||
_pluginManagementService.PluginFeatureEnabled += OnFeatureEnableStopped;
|
_pluginManagementService.PluginFeatureEnabled += OnFeatureEnableStopped;
|
||||||
_pluginManagementService.PluginFeatureEnableFailed += OnFeatureEnableStopped;
|
_pluginManagementService.PluginFeatureEnableFailed += OnFeatureEnableStopped;
|
||||||
|
|
||||||
|
FeatureInfo.Plugin.Enabled += PluginOnToggled;
|
||||||
|
FeatureInfo.Plugin.Disabled += PluginOnToggled;
|
||||||
|
|
||||||
base.OnInitialActivate();
|
base.OnInitialActivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -85,6 +91,9 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
|||||||
_pluginManagementService.PluginFeatureEnabled -= OnFeatureEnableStopped;
|
_pluginManagementService.PluginFeatureEnabled -= OnFeatureEnableStopped;
|
||||||
_pluginManagementService.PluginFeatureEnableFailed -= OnFeatureEnableStopped;
|
_pluginManagementService.PluginFeatureEnableFailed -= OnFeatureEnableStopped;
|
||||||
|
|
||||||
|
FeatureInfo.Plugin.Enabled -= PluginOnToggled;
|
||||||
|
FeatureInfo.Plugin.Disabled -= PluginOnToggled;
|
||||||
|
|
||||||
base.OnClose();
|
base.OnClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -147,6 +156,11 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
|||||||
NotifyOfPropertyChange(nameof(LoadException));
|
NotifyOfPropertyChange(nameof(LoadException));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void PluginOnToggled(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
NotifyOfPropertyChange(nameof(CanToggleEnabled));
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +1,9 @@
|
|||||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||||
|
<s:String x:Key="/Default/CodeEditing/GenerateMemberBody/DocumentationGenerationKind/@EntryValue">Inherit</s:String>
|
||||||
|
<s:Boolean x:Key="/Default/CodeEditing/GenerateMemberBody/WrapIntoRegions/@EntryValue">True</s:Boolean>
|
||||||
<s:Boolean x:Key="/Default/CodeEditing/Intellisense/CodeCompletion/IntelliSenseCompletingCharacters/CSharpCompletingCharacters/UpgradedFromVSSettings/@EntryValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeEditing/Intellisense/CodeCompletion/IntelliSenseCompletingCharacters/CSharpCompletingCharacters/UpgradedFromVSSettings/@EntryValue">True</s:Boolean>
|
||||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeObjectCreationWhenTypeNotEvident/@EntryIndexedValue">ERROR</s:String>
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeObjectCreationWhenTypeNotEvident/@EntryIndexedValue">ERROR</s:String>
|
||||||
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuspiciousTypeConversion_002EGlobal/@EntryIndexedValue">ERROR</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/CodeCleanup/RecentlyUsedProfile/@EntryValue">Built-in: Full Cleanup</s:String>
|
<s:String x:Key="/Default/CodeStyle/CodeCleanup/RecentlyUsedProfile/@EntryValue">Built-in: Full Cleanup</s:String>
|
||||||
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/APPLY_ON_COMPLETION/@EntryValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeStyle/CodeFormatting/CSharpCodeStyle/APPLY_ON_COMPLETION/@EntryValue">True</s:Boolean>
|
||||||
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
<s:String x:Key="/Default/CodeStyle/CodeFormatting/CSharpFormat/PLACE_ACCESSORHOLDER_ATTRIBUTE_ON_SAME_LINE_EX/@EntryValue">NEVER</s:String>
|
||||||
@ -128,17 +131,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>
|
||||||
@ -207,16 +199,41 @@
|
|||||||
<ImplementsInterface Immediate="True" />
|
<ImplementsInterface Immediate="True" />
|
||||||
</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>
|
||||||
|
<Region Name="Events" />
|
||||||
|
<Region Name="Event handlers" />
|
||||||
|
<Region Name="IDisposable">
|
||||||
|
<Region.GroupBy>
|
||||||
|
<ImplementsInterface />
|
||||||
|
</Region.GroupBy>
|
||||||
|
</Region>
|
||||||
</TypePattern>
|
</TypePattern>
|
||||||
</Patterns></s:String>
|
</Patterns></s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FElsewhere/@EntryIndexedValue">ERROR</s:String>
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FElsewhere/@EntryIndexedValue">ERROR</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FSimpleTypes/@EntryIndexedValue">ERROR</s:String>
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FSimpleTypes/@EntryIndexedValue">ERROR</s:String>
|
||||||
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FBuiltInTypes/@EntryIndexedValue">ERROR</s:String>
|
<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=SuggestVarOrType_005FBuiltInTypes/@EntryIndexedValue">ERROR</s:String>
|
||||||
|
<s:Boolean x:Key="/Default/CodeStyle/Generate/=DisposePattern/@KeyIndexDefined">True</s:Boolean>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Generate/=DisposePattern/Options/=ChangeDispose/@EntryIndexedValue">Replace</s:String>
|
||||||
|
<s:Boolean x:Key="/Default/CodeStyle/Generate/=Formatting/@KeyIndexDefined">True</s:Boolean>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Generate/=Formatting/Options/=UseNameOf/@EntryIndexedValue">True</s:String>
|
||||||
<s:Boolean x:Key="/Default/CodeStyle/Generate/=Implementations/@KeyIndexDefined">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeStyle/Generate/=Implementations/@KeyIndexDefined">True</s:Boolean>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Generate/=Implementations/Options/=Async/@EntryIndexedValue">True</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Generate/=Implementations/Options/=Mutable/@EntryIndexedValue">False</s:String>
|
<s:String x:Key="/Default/CodeStyle/Generate/=Implementations/Options/=Mutable/@EntryIndexedValue">False</s:String>
|
||||||
<s:Boolean x:Key="/Default/CodeStyle/Generate/=Overrides/@KeyIndexDefined">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeStyle/Generate/=Overrides/@KeyIndexDefined">True</s:Boolean>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Generate/=Overrides/Options/=Async/@EntryIndexedValue">False</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Generate/=Overrides/Options/=Mutable/@EntryIndexedValue">False</s:String>
|
<s:String x:Key="/Default/CodeStyle/Generate/=Overrides/Options/=Mutable/@EntryIndexedValue">False</s:String>
|
||||||
<s:Boolean x:Key="/Default/CodeStyle/Naming/CSharpAutoNaming/IsNotificationDisabled/@EntryValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/CodeStyle/Naming/CSharpAutoNaming/IsNotificationDisabled/@EntryValue">True</s:Boolean>
|
||||||
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=RGB/@EntryIndexedValue">RGB</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SK/@EntryIndexedValue">SK</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=SK/@EntryIndexedValue">SK</s:String>
|
||||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
|
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=UI/@EntryIndexedValue">UI</s:String>
|
||||||
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
|
<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ECSharpKeepExistingMigration/@EntryIndexedValue">True</s:Boolean>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user