1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Core - Made FloatRange and IntRange readonly structs

ColorGradient - Fixed missing subscribtions when using object list manipulation API
ColorGradient - Fixed editor VM going out of sync
This commit is contained in:
Robert 2022-07-17 23:22:45 +02:00
parent bd26f447c6
commit e385165200
19 changed files with 337 additions and 327 deletions

View File

@ -1,83 +1,79 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<PreserveCompilationContext>false</PreserveCompilationContext> <PreserveCompilationContext>false</PreserveCompilationContext>
<ShouldIncludeNativeSkiaSharp>false</ShouldIncludeNativeSkiaSharp> <ShouldIncludeNativeSkiaSharp>false</ShouldIncludeNativeSkiaSharp>
<AssemblyTitle>Artemis.Core</AssemblyTitle> <AssemblyTitle>Artemis.Core</AssemblyTitle>
<Product>Artemis Core</Product> <Product>Artemis Core</Product>
<Copyright>Copyright © Robert Beekman - 2020</Copyright> <Copyright>Copyright © Robert Beekman - 2020</Copyright>
<OutputPath>bin\</OutputPath> <OutputPath>bin\</OutputPath>
<Platforms>x64</Platforms> <Platforms>x64</Platforms>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<PlatformTarget>x64</PlatformTarget> <PlatformTarget>x64</PlatformTarget>
<DocumentationFile>bin\Artemis.Core.xml</DocumentationFile> <DocumentationFile>bin\Artemis.Core.xml</DocumentationFile>
<NoWarn></NoWarn> <NoWarn></NoWarn>
<WarningLevel>5</WarningLevel> <WarningLevel>5</WarningLevel>
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<NrtRevisionFormat>1.0-{chash:6}</NrtRevisionFormat> <NrtRevisionFormat>1.0-{chash:6}</NrtRevisionFormat>
<NrtResolveSimpleAttributes>true</NrtResolveSimpleAttributes> <NrtResolveSimpleAttributes>true</NrtResolveSimpleAttributes>
<NrtResolveInformationalAttribute>true</NrtResolveInformationalAttribute> <NrtResolveInformationalAttribute>true</NrtResolveInformationalAttribute>
<NrtResolveCopyright>true</NrtResolveCopyright> <NrtResolveCopyright>true</NrtResolveCopyright>
<NrtTagMatch>v[0-9]*</NrtTagMatch> <NrtTagMatch>v[0-9]*</NrtTagMatch>
<NrtRemoveTagV>true</NrtRemoveTagV> <NrtRemoveTagV>true</NrtRemoveTagV>
<NrtRequiredVcs>git</NrtRequiredVcs> <NrtRequiredVcs>git</NrtRequiredVcs>
<NrtShowRevision>true</NrtShowRevision> <NrtShowRevision>true</NrtShowRevision>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<AnalysisLevel>latest</AnalysisLevel> <AnalysisLevel>latest</AnalysisLevel>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<DocumentationFile>bin\Artemis.Core.xml</DocumentationFile> <DocumentationFile>bin\Artemis.Core.xml</DocumentationFile>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Artemis.Storage\Artemis.Storage.csproj"> <ProjectReference Include="..\Artemis.Storage\Artemis.Storage.csproj">
<Private>false</Private> <Private>false</Private>
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="EmbedIO" Version="3.4.3" /> <PackageReference Include="EmbedIO" Version="3.4.3"/>
<PackageReference Include="HidSharp" Version="2.1.0" /> <PackageReference Include="HidSharp" Version="2.1.0"/>
<PackageReference Include="Humanizer.Core" Version="2.14.1" /> <PackageReference Include="Humanizer.Core" Version="2.14.1"/>
<PackageReference Include="LiteDB" Version="5.0.11" /> <PackageReference Include="LiteDB" Version="5.0.11"/>
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" /> <PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0"/>
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1"/>
<PackageReference Include="Ninject" Version="3.3.4" /> <PackageReference Include="Ninject" Version="3.3.4"/>
<PackageReference Include="Ninject.Extensions.ChildKernel" Version="3.3.0" /> <PackageReference Include="Ninject.Extensions.ChildKernel" Version="3.3.0"/>
<PackageReference Include="Ninject.Extensions.Conventions" Version="3.3.0" /> <PackageReference Include="Ninject.Extensions.Conventions" Version="3.3.0"/>
<PackageReference Include="RGB.NET.Core" Version="1.0.0-prerelease.32" /> <PackageReference Include="RGB.NET.Core" Version="1.0.0-prerelease.32"/>
<PackageReference Include="RGB.NET.Layout" Version="1.0.0-prerelease.32" /> <PackageReference Include="RGB.NET.Layout" Version="1.0.0-prerelease.32"/>
<PackageReference Include="RGB.NET.Presets" Version="1.0.0-prerelease.32" /> <PackageReference Include="RGB.NET.Presets" Version="1.0.0-prerelease.32"/>
<PackageReference Include="Serilog" Version="2.10.0" /> <PackageReference Include="Serilog" Version="2.10.0"/>
<PackageReference Include="Serilog.Sinks.Console" Version="4.0.1" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.0.1"/>
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" /> <PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0"/>
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" /> <PackageReference Include="Serilog.Sinks.File" Version="5.0.0"/>
<PackageReference Include="SkiaSharp" Version="2.88.1-preview.1" /> <PackageReference Include="SkiaSharp" Version="2.88.1-preview.1"/>
<PackageReference Include="System.Buffers" Version="4.5.1" /> <PackageReference Include="System.Buffers" Version="4.5.1"/>
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" /> <PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0"/>
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" /> <PackageReference Include="System.Numerics.Vectors" Version="4.5.0"/>
<PackageReference Include="System.Reflection.Metadata" Version="5.0.0" /> <PackageReference Include="System.Reflection.Metadata" Version="5.0.0"/>
<PackageReference Include="System.ValueTuple" Version="4.5.0" /> <PackageReference Include="System.ValueTuple" Version="4.5.0"/>
<PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.1"> <PackageReference Include="Unclassified.NetRevisionTask" Version="0.4.1">
<PrivateAssets>all</PrivateAssets> <PrivateAssets>all</PrivateAssets>
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets> <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
</PackageReference> </PackageReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Update="Resources\intro-profile.json"> <None Update="Resources\intro-profile.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Update="DefaultLayouts\**"> <None Update="DefaultLayouts\**">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup>
<Folder Include="DefaultTypes\DataBindings\" />
</ItemGroup>
</Project> </Project>

View File

@ -1,91 +1,92 @@
using System.Collections.Specialized; using System.Collections.Specialized;
using System.ComponentModel;
using SkiaSharp; using SkiaSharp;
namespace Artemis.Core namespace Artemis.Core;
/// <inheritdoc />
public class ColorGradientLayerProperty : LayerProperty<ColorGradient>
{ {
/// <inheritdoc /> private ColorGradient? _subscribedGradient;
public class ColorGradientLayerProperty : LayerProperty<ColorGradient>
internal ColorGradientLayerProperty()
{ {
private ColorGradient? _subscribedGradient; KeyframesSupported = false;
DefaultValue = new ColorGradient();
}
internal ColorGradientLayerProperty() /// <summary>
/// Implicitly converts an <see cref="ColorGradientLayerProperty" /> to a <see cref="ColorGradient" />
/// </summary>
public static implicit operator ColorGradient(ColorGradientLayerProperty p)
{
return p.CurrentValue;
}
#region Overrides of LayerProperty<ColorGradient>
/// <inheritdoc />
protected override void OnCurrentValueSet()
{
// Don't allow color gradients to be null
if (BaseValue == null!)
BaseValue = new ColorGradient(DefaultValue);
if (!ReferenceEquals(_subscribedGradient, BaseValue))
{ {
KeyframesSupported = false; if (_subscribedGradient != null)
DefaultValue = new ColorGradient(); _subscribedGradient.CollectionChanged -= SubscribedGradientOnPropertyChanged;
_subscribedGradient = BaseValue;
CurrentValueSet += OnCurrentValueSet; _subscribedGradient.CollectionChanged += SubscribedGradientOnPropertyChanged;
} }
private void CreateDataBindingRegistrations() CreateDataBindingRegistrations();
{ base.OnCurrentValueSet();
DataBinding.ClearDataBindingProperties(); }
if (CurrentValue == null!)
return;
for (int index = 0; index < CurrentValue.Count; index++) #endregion
/// <inheritdoc />
protected override void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased)
{
throw new ArtemisCoreException("Color Gradients do not support keyframes.");
}
#region Overrides of LayerProperty<ColorGradient>
/// <inheritdoc />
protected override void OnInitialize()
{
// Don't allow color gradients to be null
if (BaseValue == null!)
BaseValue = new ColorGradient(DefaultValue);
base.OnInitialize();
}
#endregion
private void CreateDataBindingRegistrations()
{
DataBinding.ClearDataBindingProperties();
if (CurrentValue == null!)
return;
for (int index = 0; index < CurrentValue.Count; index++)
{
int stopIndex = index;
void Setter(SKColor value)
{ {
int stopIndex = index; CurrentValue[stopIndex].Color = value;
void Setter(SKColor value)
{
CurrentValue[stopIndex].Color = value;
}
DataBinding.RegisterDataBindingProperty(() => CurrentValue[stopIndex].Color, Setter, $"Color #{stopIndex + 1}");
}
}
/// <summary>
/// Implicitly converts an <see cref="ColorGradientLayerProperty" /> to a <see cref="ColorGradient" />
/// </summary>
public static implicit operator ColorGradient(ColorGradientLayerProperty p)
{
return p.CurrentValue;
}
/// <inheritdoc />
protected override void UpdateCurrentValue(float keyframeProgress, float keyframeProgressEased)
{
throw new ArtemisCoreException("Color Gradients do not support keyframes.");
}
private void OnCurrentValueSet(object? sender, LayerPropertyEventArgs e)
{
// Don't allow color gradients to be null
if (BaseValue == null!)
BaseValue = new ColorGradient(DefaultValue);
if (!ReferenceEquals(_subscribedGradient, BaseValue))
{
if (_subscribedGradient != null)
_subscribedGradient.CollectionChanged -= SubscribedGradientOnPropertyChanged;
_subscribedGradient = BaseValue;
_subscribedGradient.CollectionChanged += SubscribedGradientOnPropertyChanged;
} }
DataBinding.RegisterDataBindingProperty(() => CurrentValue[stopIndex].Color, Setter, $"Color #{stopIndex + 1}");
}
}
private void SubscribedGradientOnPropertyChanged(object? sender, NotifyCollectionChangedEventArgs args)
{
if (CurrentValue.Count != DataBinding.Properties.Count)
CreateDataBindingRegistrations(); CreateDataBindingRegistrations();
}
private void SubscribedGradientOnPropertyChanged(object? sender, NotifyCollectionChangedEventArgs args)
{
if (CurrentValue.Count != DataBinding.Properties.Count)
CreateDataBindingRegistrations();
}
#region Overrides of LayerProperty<ColorGradient>
/// <inheritdoc />
protected override void OnInitialize()
{
// Don't allow color gradients to be null
if (BaseValue == null!)
BaseValue = new ColorGradient(DefaultValue);
base.OnInitialize();
}
#endregion
} }
} }

View File

@ -3,17 +3,11 @@
/// <inheritdoc /> /// <inheritdoc />
public class FloatRangeLayerProperty : LayerProperty<FloatRange> public class FloatRangeLayerProperty : LayerProperty<FloatRange>
{ {
internal FloatRangeLayerProperty()
{
CurrentValueSet += OnCurrentValueSet;
DefaultValue = new FloatRange();
}
/// <inheritdoc /> /// <inheritdoc />
protected override void OnInitialize() protected override void OnInitialize()
{ {
DataBinding.RegisterDataBindingProperty(() => CurrentValue.Start, value => CurrentValue.Start = value, "Start"); DataBinding.RegisterDataBindingProperty(() => CurrentValue.Start, value => CurrentValue = new FloatRange(value, CurrentValue.End), "Start");
DataBinding.RegisterDataBindingProperty(() => CurrentValue.End, value => CurrentValue.End = value, "End"); DataBinding.RegisterDataBindingProperty(() => CurrentValue.End, value => CurrentValue = new FloatRange(CurrentValue.Start, value), "End");
} }
/// <inheritdoc /> /// <inheritdoc />
@ -22,15 +16,9 @@
float startDiff = NextKeyframe!.Value.Start - CurrentKeyframe!.Value.Start; float startDiff = NextKeyframe!.Value.Start - CurrentKeyframe!.Value.Start;
float endDiff = NextKeyframe!.Value.End - CurrentKeyframe!.Value.End; float endDiff = NextKeyframe!.Value.End - CurrentKeyframe!.Value.End;
CurrentValue = new FloatRange( CurrentValue = new FloatRange(
(int) (CurrentKeyframe!.Value.Start + startDiff * keyframeProgressEased), (float) (CurrentKeyframe!.Value.Start + startDiff * keyframeProgressEased),
(int) (CurrentKeyframe!.Value.End + endDiff * keyframeProgressEased) (float) (CurrentKeyframe!.Value.End + endDiff * keyframeProgressEased)
); );
} }
private void OnCurrentValueSet(object? sender, LayerPropertyEventArgs e)
{
// Don't allow the int range to be null
BaseValue ??= DefaultValue ?? new FloatRange();
}
} }
} }

View File

@ -3,17 +3,11 @@
/// <inheritdoc /> /// <inheritdoc />
public class IntRangeLayerProperty : LayerProperty<IntRange> public class IntRangeLayerProperty : LayerProperty<IntRange>
{ {
internal IntRangeLayerProperty()
{
CurrentValueSet += OnCurrentValueSet;
DefaultValue = new IntRange();
}
/// <inheritdoc /> /// <inheritdoc />
protected override void OnInitialize() protected override void OnInitialize()
{ {
DataBinding.RegisterDataBindingProperty(() => CurrentValue.Start, value => CurrentValue.Start = value, "Start"); DataBinding.RegisterDataBindingProperty(() => CurrentValue.Start, value => CurrentValue = new IntRange(value, CurrentValue.End), "Start");
DataBinding.RegisterDataBindingProperty(() => CurrentValue.End, value => CurrentValue.End = value, "End"); DataBinding.RegisterDataBindingProperty(() => CurrentValue.End, value => CurrentValue = new IntRange(CurrentValue.Start, value), "End");
} }
/// <inheritdoc /> /// <inheritdoc />
@ -26,11 +20,5 @@
(int) (CurrentKeyframe!.Value.End + endDiff * keyframeProgressEased) (int) (CurrentKeyframe!.Value.End + endDiff * keyframeProgressEased)
); );
} }
private void OnCurrentValueSet(object? sender, LayerPropertyEventArgs e)
{
// Don't allow the int range to be null
BaseValue ??= DefaultValue ?? new IntRange();
}
} }
} }

View File

@ -55,6 +55,21 @@ public class ColorGradient : IList<ColorGradientStop>, IList, INotifyCollectionC
} }
} }
/// <summary>
/// Creates a new instance of the <see cref="ColorGradient" /> class
/// </summary>
/// <param name="stops">The stops to copy</param>
public ColorGradient(List<ColorGradientStop> stops)
{
_stops = new List<ColorGradientStop>();
foreach (ColorGradientStop colorGradientStop in stops)
{
ColorGradientStop stop = new(colorGradientStop.Color, colorGradientStop.Position);
stop.PropertyChanged += ItemOnPropertyChanged;
_stops.Add(stop);
}
}
/// <summary> /// <summary>
/// Gets all the colors in the color gradient /// Gets all the colors in the color gradient
/// </summary> /// </summary>
@ -462,7 +477,7 @@ public class ColorGradient : IList<ColorGradientStop>, IList, INotifyCollectionC
public int Add(object? value) public int Add(object? value)
{ {
if (value is ColorGradientStop stop) if (value is ColorGradientStop stop)
_stops.Add(stop); Add(stop);
return IndexOf(value); return IndexOf(value);
} }
@ -492,14 +507,14 @@ public class ColorGradient : IList<ColorGradientStop>, IList, INotifyCollectionC
public void Insert(int index, object? value) public void Insert(int index, object? value)
{ {
if (value is ColorGradientStop stop) if (value is ColorGradientStop stop)
_stops.Insert(index, stop); Insert(index, stop);
} }
/// <inheritdoc /> /// <inheritdoc />
public void Remove(object? value) public void Remove(object? value)
{ {
if (value is ColorGradientStop stop) if (value is ColorGradientStop stop)
_stops.Remove(stop); Remove(stop);
} }
/// <inheritdoc /> /// <inheritdoc />

View File

@ -379,7 +379,7 @@ namespace Artemis.Core
UpdateDisplayCondition(); UpdateDisplayCondition();
UpdateTimeline(deltaTime); UpdateTimeline(deltaTime);
if (ShouldBeEnabled) if (ShouldBeEnabled)
Enable(); Enable();
else if (Timeline.IsFinished && !_renderCopies.Any()) else if (Timeline.IsFinished && !_renderCopies.Any())
@ -514,7 +514,7 @@ namespace Artemis.Core
}, "Failed to enable one or more effects"); }, "Failed to enable one or more effects");
if (!tryOrBreak) if (!tryOrBreak)
return; return;
Enabled = true; Enabled = true;
} }
@ -633,6 +633,7 @@ namespace Artemis.Core
if (!baseLayerEffect.Suspended) if (!baseLayerEffect.Suspended)
baseLayerEffect.InternalPreProcess(canvas, bounds, layerPaint); baseLayerEffect.InternalPreProcess(canvas, bounds, layerPaint);
} }
canvas.ClipPath(renderPath); canvas.ClipPath(renderPath);
// Restore the blend mode before doing the actual render // Restore the blend mode before doing the actual render
@ -788,10 +789,14 @@ namespace Artemis.Core
/// </summary> /// </summary>
public void ChangeLayerBrush(BaseLayerBrush? layerBrush) public void ChangeLayerBrush(BaseLayerBrush? layerBrush)
{ {
BaseLayerBrush? oldLayerBrush = LayerBrush;
General.BrushReference.SetCurrentValue(layerBrush != null ? new LayerBrushReference(layerBrush.Descriptor) : null, null); General.BrushReference.SetCurrentValue(layerBrush != null ? new LayerBrushReference(layerBrush.Descriptor) : null, null);
LayerBrush = layerBrush; LayerBrush = layerBrush;
LayerEntity.LayerBrush = new LayerBrushEntity(); LayerEntity.LayerBrush = new LayerBrushEntity();
oldLayerBrush?.InternalDisable();
if (LayerBrush != null) if (LayerBrush != null)
ActivateLayerBrush(); ActivateLayerBrush();
else else
@ -815,7 +820,12 @@ namespace Artemis.Core
General.ShapeType.IsHidden = LayerBrush != null && !LayerBrush.SupportsTransformation; General.ShapeType.IsHidden = LayerBrush != null && !LayerBrush.SupportsTransformation;
General.BlendMode.IsHidden = LayerBrush != null && !LayerBrush.SupportsTransformation; General.BlendMode.IsHidden = LayerBrush != null && !LayerBrush.SupportsTransformation;
Transform.IsHidden = LayerBrush != null && !LayerBrush.SupportsTransformation; Transform.IsHidden = LayerBrush != null && !LayerBrush.SupportsTransformation;
LayerBrush?.Update(0); if (LayerBrush != null)
{
if (!LayerBrush.Enabled)
LayerBrush.InternalEnable();
LayerBrush?.Update(0);
}
OnLayerBrushUpdated(); OnLayerBrushUpdated();
ClearBrokenState("Failed to initialize layer brush"); ClearBrokenState("Failed to initialize layer brush");

View File

@ -5,18 +5,10 @@ namespace Artemis.Core
/// <summary> /// <summary>
/// Represents a range between two single-precision floating point numbers /// Represents a range between two single-precision floating point numbers
/// </summary> /// </summary>
public class FloatRange public readonly struct FloatRange
{ {
private readonly Random _rand; private readonly Random _rand;
/// <summary>
/// Creates a new instance of the <see cref="FloatRange" /> class
/// </summary>
public FloatRange()
{
_rand = new Random();
}
/// <summary> /// <summary>
/// Creates a new instance of the <see cref="FloatRange" /> class /// Creates a new instance of the <see cref="FloatRange" /> class
/// </summary> /// </summary>
@ -31,14 +23,14 @@ namespace Artemis.Core
} }
/// <summary> /// <summary>
/// Gets or sets the start value of the range /// Gets the start value of the range
/// </summary> /// </summary>
public float Start { get; set; } public float Start { get; }
/// <summary> /// <summary>
/// Gets or sets the end value of the range /// Gets the end value of the range
/// </summary> /// </summary>
public float End { get; set; } public float End { get; }
/// <summary> /// <summary>
/// Determines whether the given value is in this range /// Determines whether the given value is in this range

View File

@ -47,7 +47,7 @@ namespace Artemis.Core
/// Gets a boolean indicating whether data bindings are supported on this type of property /// Gets a boolean indicating whether data bindings are supported on this type of property
/// </summary> /// </summary>
public bool DataBindingsSupported { get; } public bool DataBindingsSupported { get; }
/// <summary> /// <summary>
/// Gets the unique path of the property on the render element /// Gets the unique path of the property on the render element
/// </summary> /// </summary>

View File

@ -5,18 +5,10 @@ namespace Artemis.Core
/// <summary> /// <summary>
/// Represents a range between two signed integers /// Represents a range between two signed integers
/// </summary> /// </summary>
public class IntRange public readonly struct IntRange
{ {
private readonly Random _rand; private readonly Random _rand;
/// <summary>
/// Creates a new instance of the <see cref="IntRange" /> class
/// </summary>
public IntRange()
{
_rand = new Random();
}
/// <summary> /// <summary>
/// Creates a new instance of the <see cref="IntRange" /> class /// Creates a new instance of the <see cref="IntRange" /> class
/// </summary> /// </summary>
@ -31,14 +23,14 @@ namespace Artemis.Core
} }
/// <summary> /// <summary>
/// Gets or sets the start value of the range /// Gets the start value of the range
/// </summary> /// </summary>
public int Start { get; set; } public int Start { get; }
/// <summary> /// <summary>
/// Gets or sets the end value of the range /// Gets the end value of the range
/// </summary> /// </summary>
public int End { get; set; } public int End { get; }
/// <summary> /// <summary>
/// Determines whether the given value is in this range /// Determines whether the given value is in this range

View File

@ -261,7 +261,7 @@ namespace Artemis.Core
/// <summary> /// <summary>
/// Gets whether keyframes are supported on this type of property /// Gets whether keyframes are supported on this type of property
/// </summary> /// </summary>
public bool KeyframesSupported { get; protected internal set; } = true; public bool KeyframesSupported { get; protected set; } = true;
/// <summary> /// <summary>
/// Gets or sets whether keyframes are enabled on this property, has no effect if <see cref="KeyframesSupported" /> is /// Gets or sets whether keyframes are enabled on this property, has no effect if <see cref="KeyframesSupported" /> is

View File

@ -39,8 +39,6 @@ namespace Artemis.Core.LayerBrushes
PropertyGroupDescriptionAttribute groupDescription = new() {Identifier = "Brush", Name = Descriptor.DisplayName, Description = Descriptor.Description}; PropertyGroupDescriptionAttribute groupDescription = new() {Identifier = "Brush", Name = Descriptor.DisplayName, Description = Descriptor.Description};
Properties.Initialize(Layer, null, groupDescription, propertyGroupEntity); Properties.Initialize(Layer, null, groupDescription, propertyGroupEntity);
PropertiesInitialized = true; PropertiesInitialized = true;
EnableLayerBrush();
} }
} }
} }

View File

@ -3,8 +3,8 @@
<OutputType>Library</OutputType> <OutputType>Library</OutputType>
<TargetFramework>net6.0</TargetFramework> <TargetFramework>net6.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<ApplicationIcon /> <ApplicationIcon/>
<StartupObject /> <StartupObject/>
<OutputPath>bin\</OutputPath> <OutputPath>bin\</OutputPath>
<PlatformTarget>x64</PlatformTarget> <PlatformTarget>x64</PlatformTarget>
<Platforms>x64</Platforms> <Platforms>x64</Platforms>
@ -15,20 +15,20 @@
<ItemGroup> <ItemGroup>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.15" /> <PackageReference Include="Avalonia" Version="0.10.15"/>
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.15" /> <PackageReference Include="Avalonia.Diagnostics" Version="0.10.15"/>
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.15" /> <PackageReference Include="Avalonia.ReactiveUI" Version="0.10.15"/>
<PackageReference Include="Avalonia.Xaml.Behaviors" Version="0.10.14" /> <PackageReference Include="Avalonia.Xaml.Behaviors" Version="0.10.14"/>
<PackageReference Include="DynamicData" Version="7.8.6" /> <PackageReference Include="DynamicData" Version="7.8.6"/>
<PackageReference Include="FluentAvaloniaUI" Version="1.4.1" /> <PackageReference Include="FluentAvaloniaUI" Version="1.4.1"/>
<PackageReference Include="Material.Icons.Avalonia" Version="1.0.2" /> <PackageReference Include="Material.Icons.Avalonia" Version="1.0.2"/>
<PackageReference Include="ReactiveUI" Version="17.1.50" /> <PackageReference Include="ReactiveUI" Version="17.1.50"/>
<PackageReference Include="ReactiveUI.Validation" Version="2.2.1" /> <PackageReference Include="ReactiveUI.Validation" Version="2.2.1"/>
<PackageReference Include="RGB.NET.Core" Version="1.0.0-prerelease.32" /> <PackageReference Include="RGB.NET.Core" Version="1.0.0-prerelease.32"/>
<PackageReference Include="SkiaSharp" Version="2.88.1-preview.1" /> <PackageReference Include="SkiaSharp" Version="2.88.1-preview.1"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" /> <ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Update="Controls\HotkeyBox.axaml.cs"> <Compile Update="Controls\HotkeyBox.axaml.cs">

View File

@ -24,7 +24,7 @@ public class GradientPickerButton : TemplatedControl
/// Gets or sets the color gradient. /// Gets or sets the color gradient.
/// </summary> /// </summary>
public static readonly StyledProperty<ColorGradient?> ColorGradientProperty = public static readonly StyledProperty<ColorGradient?> ColorGradientProperty =
AvaloniaProperty.Register<GradientPickerButton, ColorGradient?>(nameof(ColorGradient), notifying: ColorGradientChanged, defaultValue: ColorGradient.GetUnicornBarf()); AvaloniaProperty.Register<GradientPickerButton, ColorGradient?>(nameof(ColorGradient), notifying: ColorGradientChanged);
/// <summary> /// <summary>
/// Gets or sets a boolean indicating whether the gradient picker should be in compact mode or not. /// Gets or sets a boolean indicating whether the gradient picker should be in compact mode or not.
@ -108,7 +108,8 @@ public class GradientPickerButton : TemplatedControl
private static void ColorGradientChanged(IAvaloniaObject sender, bool before) private static void ColorGradientChanged(IAvaloniaObject sender, bool before)
{ {
(sender as GradientPickerButton)?.Subscribe(); if (!before)
(sender as GradientPickerButton)?.Subscribe();
} }
private void Subscribe() private void Subscribe()

View File

@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Artemis.Core;
namespace Artemis.UI.Shared.Services.ProfileEditor.Commands;
/// <summary>
/// Represents a profile editor command that can be used to update a layer property of type <typeparamref name="T" />.
/// </summary>
public class UpdateColorGradient : IProfileEditorCommand
{
private readonly ColorGradient _colorGradient;
private readonly List<ColorGradientStop> _stops;
private readonly List<ColorGradientStop> _originalStops;
/// <summary>
/// Creates a new instance of the <see cref="UpdateColorGradient" /> class.
/// </summary>
public UpdateColorGradient(ColorGradient colorGradient, List<ColorGradientStop> stops, List<ColorGradientStop>? originalStops)
{
_colorGradient = colorGradient;
_stops = stops;
_originalStops = originalStops ?? _colorGradient.Select(s => new ColorGradientStop(s.Color, s.Position)).ToList();
}
#region Implementation of IProfileEditorCommand
/// <inheritdoc />
public string DisplayName => "Update color gradient";
/// <inheritdoc />
public void Execute()
{
_colorGradient.Clear();
foreach (ColorGradientStop colorGradientStop in _stops)
_colorGradient.Add(colorGradientStop);
}
/// <inheritdoc />
public void Undo()
{
_colorGradient.Clear();
foreach (ColorGradientStop colorGradientStop in _originalStops)
_colorGradient.Add(colorGradientStop);
}
#endregion
}

View File

@ -8,44 +8,44 @@
<Platforms>x64</Platforms> <Platforms>x64</Platforms>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<AvaloniaResource Include="Assets\**" /> <AvaloniaResource Include="Assets\**"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<None Remove="Artemis.UI.Avalonia.csproj.DotSettings" /> <None Remove="Artemis.UI.Avalonia.csproj.DotSettings"/>
<None Remove="Artemis.UI.csproj.DotSettings" /> <None Remove="Artemis.UI.csproj.DotSettings"/>
<None Remove="Assets\Images\Logo\application.ico" /> <None Remove="Assets\Images\Logo\application.ico"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.15" /> <PackageReference Include="Avalonia" Version="0.10.15"/>
<PackageReference Include="Avalonia.Controls.PanAndZoom" Version="10.14.0" /> <PackageReference Include="Avalonia.Controls.PanAndZoom" Version="10.14.0"/>
<PackageReference Include="Avalonia.Desktop" Version="0.10.15" /> <PackageReference Include="Avalonia.Desktop" Version="0.10.15"/>
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.15" /> <PackageReference Include="Avalonia.Diagnostics" Version="0.10.15"/>
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.15" /> <PackageReference Include="Avalonia.ReactiveUI" Version="0.10.15"/>
<PackageReference Include="Avalonia.Xaml.Behaviors" Version="0.10.14" /> <PackageReference Include="Avalonia.Xaml.Behaviors" Version="0.10.14"/>
<PackageReference Include="DynamicData" Version="7.8.6" /> <PackageReference Include="DynamicData" Version="7.8.6"/>
<PackageReference Include="FluentAvaloniaUI" Version="1.4.1" /> <PackageReference Include="FluentAvaloniaUI" Version="1.4.1"/>
<PackageReference Include="Flurl.Http" Version="3.2.4" /> <PackageReference Include="Flurl.Http" Version="3.2.4"/>
<PackageReference Include="Live.Avalonia" Version="1.3.1" /> <PackageReference Include="Live.Avalonia" Version="1.3.1"/>
<PackageReference Include="Material.Icons.Avalonia" Version="1.0.2" /> <PackageReference Include="Material.Icons.Avalonia" Version="1.0.2"/>
<PackageReference Include="ReactiveUI" Version="17.1.50" /> <PackageReference Include="ReactiveUI" Version="17.1.50"/>
<PackageReference Include="ReactiveUI.Validation" Version="2.2.1" /> <PackageReference Include="ReactiveUI.Validation" Version="2.2.1"/>
<PackageReference Include="RGB.NET.Core" Version="1.0.0-prerelease.32" /> <PackageReference Include="RGB.NET.Core" Version="1.0.0-prerelease.32"/>
<PackageReference Include="RGB.NET.Layout" Version="1.0.0-prerelease.32" /> <PackageReference Include="RGB.NET.Layout" Version="1.0.0-prerelease.32"/>
<PackageReference Include="SkiaSharp" Version="2.88.1-preview.1" /> <PackageReference Include="SkiaSharp" Version="2.88.1-preview.1"/>
<PackageReference Include="Splat.Ninject" Version="14.1.45" /> <PackageReference Include="Splat.Ninject" Version="14.1.45"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" /> <ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj"/>
<ProjectReference Include="..\Artemis.UI.Shared\Artemis.UI.Shared.csproj" /> <ProjectReference Include="..\Artemis.UI.Shared\Artemis.UI.Shared.csproj"/>
<ProjectReference Include="..\Artemis.VisualScripting\Artemis.VisualScripting.csproj" /> <ProjectReference Include="..\Artemis.VisualScripting\Artemis.VisualScripting.csproj"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Content Include="Assets\Images\Logo\bow-white.ico" /> <Content Include="Assets\Images\Logo\bow-white.ico"/>
<Content Include="Assets\Images\Logo\bow.ico" /> <Content Include="Assets\Images\Logo\bow.ico"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Resource Include="Assets\Images\Logo\bow-black.ico" /> <Resource Include="Assets\Images\Logo\bow-black.ico"/>
<Resource Include="Assets\Images\Logo\bow-white.ico" /> <Resource Include="Assets\Images\Logo\bow-white.ico"/>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Update="DefaultTypes\PropertyInput\StringPropertyInputView.axaml.cs"> <Compile Update="DefaultTypes\PropertyInput\StringPropertyInputView.axaml.cs">
@ -72,8 +72,8 @@
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Update="Screens\Scripting\Dialogs\ScriptConfigurationEditView.axaml.cs"> <Compile Update="Screens\Scripting\Dialogs\ScriptConfigurationEditView.axaml.cs">
<DependentUpon>ScriptConfigurationEditView.axaml</DependentUpon> <DependentUpon>ScriptConfigurationEditView.axaml</DependentUpon>
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -9,7 +9,7 @@
x:DataType="propertyInput:ColorGradientPropertyInputViewModel"> x:DataType="propertyInput:ColorGradientPropertyInputViewModel">
<gradientPicker:GradientPickerButton Classes="condensed" <gradientPicker:GradientPickerButton Classes="condensed"
Width="200" Width="200"
ColorGradient="{CompiledBinding ColorGradient}" ColorGradient="{CompiledBinding InputValue}"
VerticalAlignment="Center" VerticalAlignment="Center"
FlyoutOpened="GradientPickerButton_OnFlyoutOpened" FlyoutOpened="GradientPickerButton_OnFlyoutOpened"
FlyoutClosed="GradientPickerButton_OnFlyoutClosed"/> FlyoutClosed="GradientPickerButton_OnFlyoutClosed"/>

View File

@ -1,4 +1,6 @@
using Artemis.Core; using System.Collections.Generic;
using System.Linq;
using Artemis.Core;
using Artemis.UI.Shared.Services.ProfileEditor; using Artemis.UI.Shared.Services.ProfileEditor;
using Artemis.UI.Shared.Services.ProfileEditor.Commands; using Artemis.UI.Shared.Services.ProfileEditor.Commands;
using Artemis.UI.Shared.Services.PropertyInput; using Artemis.UI.Shared.Services.PropertyInput;
@ -9,37 +11,19 @@ namespace Artemis.UI.DefaultTypes.PropertyInput;
public class ColorGradientPropertyInputViewModel : PropertyInputViewModel<ColorGradient> public class ColorGradientPropertyInputViewModel : PropertyInputViewModel<ColorGradient>
{ {
private ColorGradient _colorGradient = null!; private ColorGradient _colorGradient = null!;
private ColorGradient? _originalGradient; private List<ColorGradientStop>? _originalStops;
public ColorGradientPropertyInputViewModel(LayerProperty<ColorGradient> layerProperty, IProfileEditorService profileEditorService, IPropertyInputService propertyInputService) public ColorGradientPropertyInputViewModel(LayerProperty<ColorGradient> layerProperty, IProfileEditorService profileEditorService, IPropertyInputService propertyInputService)
: base(layerProperty, profileEditorService, propertyInputService) : base(layerProperty, profileEditorService, propertyInputService)
{ {
} }
public ColorGradient ColorGradient
{
get => _colorGradient;
set => this.RaiseAndSetIfChanged(ref _colorGradient, value);
}
protected override void OnInputValueChanged()
{
ColorGradient = new ColorGradient(InputValue);
}
#region Overrides of PropertyInputViewModel<ColorGradient> #region Overrides of PropertyInputViewModel<ColorGradient>
/// <inheritdoc /> /// <inheritdoc />
public override void StartPreview() public override void StartPreview()
{ {
_originalGradient = LayerProperty.CurrentValue; _originalStops = InputValue?.Select(s => new ColorGradientStop(s.Color, s.Position)).ToList();
// Set the property value to the gradient being edited by the picker, this will cause any updates to show right away because
// ColorGradient is a reference type
LayerProperty.CurrentValue = ColorGradient;
// This won't fly if we ever support keyframes but at that point ColorGradient would have to be a value type anyway and this
// whole VM no longer makes sense
} }
/// <inheritdoc /> /// <inheritdoc />
@ -51,29 +35,41 @@ public class ColorGradientPropertyInputViewModel : PropertyInputViewModel<ColorG
/// <inheritdoc /> /// <inheritdoc />
public override void ApplyPreview() public override void ApplyPreview()
{ {
if (_originalGradient == null) // If the new stops are equal to the old ones, nothing changes
if (InputValue == null || _originalStops == null || !HasPreviewChanges())
return; return;
// Make sure something actually changed ProfileEditorService.ExecuteCommand(new UpdateColorGradient(InputValue, InputValue.ToList(), _originalStops));
if (Equals(ColorGradient, _originalGradient)) _originalStops = null;
LayerProperty.CurrentValue = _originalGradient;
else
// Update the gradient for realsies, giving the command a reference to the old gradient
ProfileEditorService.ExecuteCommand(new UpdateLayerProperty<ColorGradient>(LayerProperty, ColorGradient, _originalGradient, Time));
_originalGradient = null;
} }
/// <inheritdoc /> /// <inheritdoc />
public override void DiscardPreview() public override void DiscardPreview()
{ {
if (_originalGradient == null) if (InputValue == null || _originalStops == null)
return; return;
// Put the old gradient back // Put the old gradient back
InputValue = _originalGradient; InputValue.Clear();
ColorGradient = new ColorGradient(InputValue); foreach (ColorGradientStop colorGradientStop in _originalStops)
InputValue.Add(colorGradientStop);
_originalStops = null;
} }
private bool HasPreviewChanges()
{
if (InputValue == null || _originalStops == null)
return false;
if (InputValue.Count != _originalStops.Count)
return true;
for (int i = 0; i < InputValue.Count; i++)
if (!Equals(InputValue[i], _originalStops[i]))
return true;
return false;
}
#endregion #endregion
} }

View File

@ -30,28 +30,20 @@ public class FloatRangePropertyInputViewModel : PropertyInputViewModel<FloatRang
public float Start public float Start
{ {
get => InputValue?.Start ?? 0; get => InputValue.Start;
set set
{ {
if (InputValue == null) InputValue = new FloatRange(value, InputValue.End);
InputValue = new FloatRange(value, value + 1);
else
InputValue.Start = value;
this.RaisePropertyChanged(nameof(Start)); this.RaisePropertyChanged(nameof(Start));
} }
} }
public float End public float End
{ {
get => InputValue?.End ?? 0; get => InputValue.End;
set set
{ {
if (InputValue == null) InputValue = new FloatRange(InputValue.Start, value);
InputValue = new FloatRange(value - 1, value);
else
InputValue.End = value;
this.RaisePropertyChanged(nameof(End)); this.RaisePropertyChanged(nameof(End));
} }
} }

View File

@ -30,28 +30,20 @@ public class IntRangePropertyInputViewModel : PropertyInputViewModel<IntRange>
public int Start public int Start
{ {
get => InputValue?.Start ?? 0; get => InputValue.Start;
set set
{ {
if (InputValue == null) InputValue = new IntRange(value, InputValue.End);
InputValue = new IntRange(value, value + 1);
else
InputValue.Start = value;
this.RaisePropertyChanged(nameof(Start)); this.RaisePropertyChanged(nameof(Start));
} }
} }
public int End public int End
{ {
get => InputValue?.End ?? 0; get => InputValue.End;
set set
{ {
if (InputValue == null) InputValue = new IntRange(InputValue.Start, value);
InputValue = new IntRange(value - 1, value);
else
InputValue.End = value;
this.RaisePropertyChanged(nameof(End)); this.RaisePropertyChanged(nameof(End));
} }
} }