mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Core - Add HidSharp to force plugins to share the HidSharp types
Core - For now, set default log level to debug ColorGradient- Improved GetColor performance ColorGradient - GetColor now handles colors not between two stops properly Home - Fix links Plugins - Only allow layer property registration through Brushes Color brush - Default to solid color
This commit is contained in:
parent
8c3212451b
commit
9f8fc9f70e
@ -22,6 +22,7 @@
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Ben.Demystifier" Version="0.1.6" />
|
||||
<PackageReference Include="Castle.Core" Version="4.4.0" />
|
||||
<PackageReference Include="HidSharp" Version="2.1.0" />
|
||||
<PackageReference Include="LiteDB" Version="5.0.7" />
|
||||
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.2.0" />
|
||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||
|
||||
@ -28,6 +28,54 @@ namespace Artemis.Core.Models.Profile
|
||||
return Stops.OrderBy(c => c.Position).Select(c => c.Position).ToArray();
|
||||
}
|
||||
|
||||
public void OnColorValuesUpdated()
|
||||
{
|
||||
OnPropertyChanged(nameof(Stops));
|
||||
}
|
||||
|
||||
public SKColor GetColor(float position)
|
||||
{
|
||||
if (!Stops.Any())
|
||||
return SKColor.Empty;
|
||||
|
||||
var stops = Stops.OrderBy(x => x.Position).ToArray();
|
||||
if (position <= 0) return stops[0].Color;
|
||||
if (position >= 1) return stops[^1].Color;
|
||||
ColorGradientStop left = stops[0], right = null;
|
||||
foreach (var stop in stops)
|
||||
{
|
||||
if (stop.Position >= position)
|
||||
{
|
||||
right = stop;
|
||||
break;
|
||||
}
|
||||
|
||||
left = stop;
|
||||
}
|
||||
|
||||
if (right == null || left == right)
|
||||
return left.Color;
|
||||
|
||||
position = (float) Math.Round((position - left.Position) / (right.Position - left.Position), 2);
|
||||
var a = (byte) ((right.Color.Alpha - left.Color.Alpha) * position + left.Color.Alpha);
|
||||
var r = (byte) ((right.Color.Red - left.Color.Red) * position + left.Color.Red);
|
||||
var g = (byte) ((right.Color.Green - left.Color.Green) * position + left.Color.Green);
|
||||
var b = (byte) ((right.Color.Blue - left.Color.Blue) * position + left.Color.Blue);
|
||||
return new SKColor(r, g, b, a);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// [PH] Looping through HSV, adds 8 rainbow colors
|
||||
/// </summary>
|
||||
public void MakeFabulous()
|
||||
{
|
||||
for (var i = 0; i < 9; i++)
|
||||
{
|
||||
var color = i != 8 ? SKColor.FromHsv(i * 32, 100, 100) : SKColor.FromHsv(0, 100, 100);
|
||||
Stops.Add(new ColorGradientStop(color, 0.125f * i));
|
||||
}
|
||||
}
|
||||
|
||||
#region PropertyChanged
|
||||
|
||||
public event PropertyChangedEventHandler PropertyChanged;
|
||||
@ -39,51 +87,6 @@ namespace Artemis.Core.Models.Profile
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void OnColorValuesUpdated()
|
||||
{
|
||||
OnPropertyChanged(nameof(Stops));
|
||||
}
|
||||
|
||||
public SKColor GetColor(float position)
|
||||
{
|
||||
if (!Stops.Any())
|
||||
return SKColor.Empty;
|
||||
|
||||
var point = Stops.FirstOrDefault(f => f.Position == position);
|
||||
if (point != null) return point.Color;
|
||||
|
||||
var before = Stops.First(w => w.Position == Stops.Min(m => m.Position));
|
||||
var after = Stops.First(w => w.Position == Stops.Max(m => m.Position));
|
||||
|
||||
foreach (var gs in Stops)
|
||||
{
|
||||
if (gs.Position < position && gs.Position > before.Position)
|
||||
before = gs;
|
||||
|
||||
if (gs.Position >= position && gs.Position < after.Position)
|
||||
after = gs;
|
||||
}
|
||||
|
||||
return new SKColor(
|
||||
(byte) ((position - before.Position) * (after.Color.Red - before.Color.Red) / (after.Position - before.Position) + before.Color.Red),
|
||||
(byte) ((position - before.Position) * (after.Color.Green - before.Color.Green) / (after.Position - before.Position) + before.Color.Green),
|
||||
(byte) ((position - before.Position) * (after.Color.Blue - before.Color.Blue) / (after.Position - before.Position) + before.Color.Blue),
|
||||
(byte) ((position - before.Position) * (after.Color.Alpha - before.Color.Alpha) / (after.Position - before.Position) + before.Color.Alpha)
|
||||
);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// [PH] Looping through HSV, adds 8 rainbow colors
|
||||
/// </summary>
|
||||
public void MakeFabulous()
|
||||
{
|
||||
for (var i = 0; i < 9; i++)
|
||||
{
|
||||
var color = i != 8 ? SKColor.FromHsv(i * 32, 100, 100) : SKColor.FromHsv(0, 100, 100);
|
||||
Stops.Add(new ColorGradientStop(color, 0.125f * i));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class ColorGradientStop : INotifyPropertyChanged
|
||||
|
||||
@ -41,32 +41,6 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
||||
return GetEnumerator();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the provided layer property from the layer.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of value of the layer property</typeparam>
|
||||
/// <param name="layerProperty">The property to remove from the layer</param>
|
||||
public void RemoveLayerProperty<T>(LayerProperty<T> layerProperty)
|
||||
{
|
||||
RemoveLayerProperty((BaseLayerProperty) layerProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the provided layer property from the layer.
|
||||
/// </summary>
|
||||
/// <param name="layerProperty">The property to remove from the layer</param>
|
||||
public void RemoveLayerProperty(BaseLayerProperty layerProperty)
|
||||
{
|
||||
if (!_properties.ContainsKey((layerProperty.PluginInfo.Guid, layerProperty.Id)))
|
||||
throw new ArtemisCoreException($"Could not find a property with ID {layerProperty.Id}.");
|
||||
|
||||
var property = _properties[(layerProperty.PluginInfo.Guid, layerProperty.Id)];
|
||||
property.Parent?.Children.Remove(property);
|
||||
_properties.Remove((layerProperty.PluginInfo.Guid, layerProperty.Id));
|
||||
|
||||
OnLayerPropertyRemoved(new LayerPropertyEventArgs(property));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// If found, returns the <see cref="LayerProperty{T}" /> matching the provided ID
|
||||
/// </summary>
|
||||
@ -82,7 +56,33 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
||||
var property = _properties[(pluginInfo.Guid, id)];
|
||||
if (property.Type != typeof(T))
|
||||
throw new ArtemisCoreException($"Property type mismatch. Expected property {property} to have type {typeof(T)} but it has {property.Type} instead.");
|
||||
return (LayerProperty<T>) _properties[(pluginInfo.Guid, id)];
|
||||
return (LayerProperty<T>)_properties[(pluginInfo.Guid, id)];
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the provided layer property from the layer.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of value of the layer property</typeparam>
|
||||
/// <param name="layerProperty">The property to remove from the layer</param>
|
||||
internal void RemoveLayerProperty<T>(LayerProperty<T> layerProperty)
|
||||
{
|
||||
RemoveLayerProperty((BaseLayerProperty) layerProperty);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the provided layer property from the layer.
|
||||
/// </summary>
|
||||
/// <param name="layerProperty">The property to remove from the layer</param>
|
||||
internal void RemoveLayerProperty(BaseLayerProperty layerProperty)
|
||||
{
|
||||
if (!_properties.ContainsKey((layerProperty.PluginInfo.Guid, layerProperty.Id)))
|
||||
throw new ArtemisCoreException($"Could not find a property with ID {layerProperty.Id}.");
|
||||
|
||||
var property = _properties[(layerProperty.PluginInfo.Guid, layerProperty.Id)];
|
||||
property.Parent?.Children.Remove(property);
|
||||
_properties.Remove((layerProperty.PluginInfo.Guid, layerProperty.Id));
|
||||
|
||||
OnLayerPropertyRemoved(new LayerPropertyEventArgs(property));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -92,7 +92,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
||||
/// <typeparam name="T">The type of value of the layer property</typeparam>
|
||||
/// <param name="layerProperty">The property to apply to the layer</param>
|
||||
/// <returns>True if an existing value was found and applied, otherwise false.</returns>
|
||||
public bool RegisterLayerProperty<T>(LayerProperty<T> layerProperty)
|
||||
internal bool RegisterLayerProperty<T>(LayerProperty<T> layerProperty)
|
||||
{
|
||||
return RegisterLayerProperty((BaseLayerProperty) layerProperty);
|
||||
}
|
||||
@ -103,7 +103,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
||||
/// </summary>
|
||||
/// <param name="layerProperty">The property to apply to the layer</param>
|
||||
/// <returns>True if an existing value was found and applied, otherwise false.</returns>
|
||||
public bool RegisterLayerProperty(BaseLayerProperty layerProperty)
|
||||
internal bool RegisterLayerProperty(BaseLayerProperty layerProperty)
|
||||
{
|
||||
if (_properties.ContainsKey((layerProperty.PluginInfo.Guid, layerProperty.Id)))
|
||||
throw new ArtemisCoreException($"Duplicate property ID detected. Layer already contains a property with ID {layerProperty.Id}.");
|
||||
|
||||
@ -2,6 +2,7 @@
|
||||
using System.Linq;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.Core.Models.Profile.LayerProperties;
|
||||
using Artemis.Core.Plugins.Exceptions;
|
||||
using Artemis.Core.Services.Interfaces;
|
||||
using SkiaSharp;
|
||||
|
||||
@ -35,7 +36,7 @@ namespace Artemis.Core.Plugins.LayerBrush
|
||||
/// <summary>
|
||||
/// The main method of rendering anything to the layer. The provided <see cref="SKCanvas" /> is specific to the layer
|
||||
/// and matches it's width and height.
|
||||
/// <para>Called during rendering, in the order configured on the layer</para>
|
||||
/// <para>Called during rendering or layer preview, in the order configured on the layer</para>
|
||||
/// </summary>
|
||||
/// <param name="canvas">The layer canvas</param>
|
||||
/// <param name="canvasInfo"></param>
|
||||
@ -77,6 +78,22 @@ namespace Artemis.Core.Plugins.LayerBrush
|
||||
/// <returns>The layer property</returns>
|
||||
protected LayerProperty<T> RegisterLayerProperty<T>(string id, string name, string description, T defaultValue = default)
|
||||
{
|
||||
// Check if the property already exists
|
||||
var existing = Layer.Properties.FirstOrDefault(p =>
|
||||
p.PluginInfo.Guid == Descriptor.LayerBrushProvider.PluginInfo.Guid &&
|
||||
p.Id == id &&
|
||||
p.Name == name &&
|
||||
p.Description == description);
|
||||
|
||||
if (existing != null)
|
||||
{
|
||||
// If it exists and the types match, return the existing property
|
||||
if (existing.Type == typeof(T))
|
||||
return (LayerProperty<T>) existing;
|
||||
// If it exists and the types are different, something is wrong
|
||||
throw new ArtemisPluginException($"Cannot register the property {id} with different types twice.");
|
||||
}
|
||||
|
||||
var property = new LayerProperty<T>(Layer, Descriptor.LayerBrushProvider.PluginInfo, Layer.Properties.BrushReference.Parent, id, name, description)
|
||||
{
|
||||
Value = defaultValue
|
||||
|
||||
@ -38,7 +38,7 @@ namespace Artemis.Core.Services
|
||||
_rgbService = rgbService;
|
||||
_surfaceService = surfaceService;
|
||||
_profileService = profileService;
|
||||
_loggingLevel = settingsService.GetSetting("Core.LoggingLevel", LogEventLevel.Information);
|
||||
_loggingLevel = settingsService.GetSetting("Core.LoggingLevel", LogEventLevel.Debug);
|
||||
|
||||
_rgbService.Surface.Updating += SurfaceOnUpdating;
|
||||
_rgbService.Surface.Updated += SurfaceOnUpdated;
|
||||
|
||||
@ -28,6 +28,8 @@ namespace Artemis.Core.Services.Interfaces
|
||||
/// </summary>
|
||||
IReadOnlyCollection<IRGBDevice> LoadedDevices { get; }
|
||||
|
||||
TimerUpdateTrigger UpdateTrigger { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Adds the given device provider to the <see cref="Surface" />
|
||||
/// </summary>
|
||||
|
||||
@ -20,7 +20,6 @@ namespace Artemis.Core.Services
|
||||
private readonly PluginSetting<double> _renderScaleSetting;
|
||||
private readonly PluginSetting<int> _sampleSizeSetting;
|
||||
private readonly PluginSetting<int> _targetFrameRateSetting;
|
||||
private readonly TimerUpdateTrigger _updateTrigger;
|
||||
private ListLedGroup _surfaceLedGroup;
|
||||
|
||||
internal RgbService(ILogger logger, ISettingsService settingsService)
|
||||
@ -37,17 +36,16 @@ namespace Artemis.Core.Services
|
||||
_renderScaleSetting.SettingChanged += RenderScaleSettingOnSettingChanged;
|
||||
_targetFrameRateSetting.SettingChanged += TargetFrameRateSettingOnSettingChanged;
|
||||
_loadedDevices = new List<IRGBDevice>();
|
||||
_updateTrigger = new TimerUpdateTrigger {UpdateFrequency = 1.0 / _targetFrameRateSetting.Value};
|
||||
Surface.RegisterUpdateTrigger(_updateTrigger);
|
||||
UpdateTrigger = new TimerUpdateTrigger {UpdateFrequency = 1.0 / _targetFrameRateSetting.Value};
|
||||
Surface.RegisterUpdateTrigger(UpdateTrigger);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public RGBSurface Surface { get; set; }
|
||||
|
||||
public TimerUpdateTrigger UpdateTrigger { get; }
|
||||
public BitmapBrush BitmapBrush { get; private set; }
|
||||
|
||||
public IReadOnlyCollection<IRGBDevice> LoadedDevices => _loadedDevices.AsReadOnly();
|
||||
|
||||
public double RenderScale => _renderScaleSetting.Value;
|
||||
|
||||
public void AddDeviceProvider(IRGBDeviceProvider deviceProvider)
|
||||
@ -82,9 +80,9 @@ namespace Artemis.Core.Services
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
Surface.UnregisterUpdateTrigger(_updateTrigger);
|
||||
Surface.UnregisterUpdateTrigger(UpdateTrigger);
|
||||
|
||||
_updateTrigger.Dispose();
|
||||
UpdateTrigger.Dispose();
|
||||
Surface.Dispose();
|
||||
}
|
||||
|
||||
@ -95,7 +93,7 @@ namespace Artemis.Core.Services
|
||||
|
||||
private void TargetFrameRateSettingOnSettingChanged(object sender, EventArgs e)
|
||||
{
|
||||
_updateTrigger.UpdateFrequency = 1.0 / _targetFrameRateSetting.Value;
|
||||
UpdateTrigger.UpdateFrequency = 1.0 / _targetFrameRateSetting.Value;
|
||||
}
|
||||
|
||||
private void SurfaceOnException(ExceptionEventArgs args)
|
||||
|
||||
@ -95,6 +95,7 @@ namespace Artemis.Core.Services.Storage
|
||||
// Update the RGB service's graphics decorator to work with the new surface entity
|
||||
_rgbService.UpdateSurfaceLedGroup();
|
||||
OnActiveSurfaceConfigurationChanged(new SurfaceConfigurationEventArgs(ActiveSurface));
|
||||
|
||||
}
|
||||
|
||||
public void UpdateSurfaceConfiguration(ArtemisSurface surface, bool includeDevices)
|
||||
|
||||
@ -25,6 +25,7 @@
|
||||
<PackageReference Include="MaterialDesignThemes" Version="3.1.0" />
|
||||
<PackageReference Include="Ninject" Version="3.3.4" />
|
||||
<PackageReference Include="Ninject.Extensions.Conventions" Version="3.3.0" />
|
||||
<PackageReference Include="PropertyChanged.Fody" Version="3.2.8" />
|
||||
<PackageReference Include="SkiaSharp" Version="1.68.2-preview.29" />
|
||||
<PackageReference Include="SkiaSharp.Views.WPF" Version="1.68.2-preview.29" />
|
||||
<PackageReference Include="Stylet" Version="1.3.1" />
|
||||
|
||||
3
src/Artemis.UI.Shared/FodyWeavers.xml
Normal file
3
src/Artemis.UI.Shared/FodyWeavers.xml
Normal file
@ -0,0 +1,3 @@
|
||||
<Weavers xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="FodyWeavers.xsd">
|
||||
<PropertyChanged />
|
||||
</Weavers>
|
||||
64
src/Artemis.UI.Shared/FodyWeavers.xsd
Normal file
64
src/Artemis.UI.Shared/FodyWeavers.xsd
Normal file
@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
|
||||
<!-- This file was generated by Fody. Manual changes to this file will be lost when your project is rebuilt. -->
|
||||
<xs:element name="Weavers">
|
||||
<xs:complexType>
|
||||
<xs:all>
|
||||
<xs:element name="PropertyChanged" minOccurs="0" maxOccurs="1">
|
||||
<xs:complexType>
|
||||
<xs:attribute name="InjectOnPropertyNameChanged" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to control if the On_PropertyName_Changed feature is enabled.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="EventInvokerNames" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to change the name of the method that fires the notify event. This is a string that accepts multiple values in a comma separated form.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="CheckForEquality" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to control if equality checks should be inserted. If false, equality checking will be disabled for the project.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="CheckForEqualityUsingBaseEquals" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to control if equality checks should use the Equals method resolved from the base class.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="UseStaticEqualsFromBase" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to control if equality checks should use the static Equals method resolved from the base class.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="SuppressWarnings" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to turn off build warnings from this weaver.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="SuppressOnPropertyNameChangedWarning" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>Used to turn off build warnings about mismatched On_PropertyName_Changed methods.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:all>
|
||||
<xs:attribute name="VerifyAssembly" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>'true' to run assembly verification (PEVerify) on the target assembly after all weavers have been executed.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="VerifyIgnoreCodes" type="xs:string">
|
||||
<xs:annotation>
|
||||
<xs:documentation>A comma-separated list of error codes that can be safely ignored in assembly verification.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
<xs:attribute name="GenerateXsd" type="xs:boolean">
|
||||
<xs:annotation>
|
||||
<xs:documentation>'false' to turn off automatic generation of the XML Schema file.</xs:documentation>
|
||||
</xs:annotation>
|
||||
</xs:attribute>
|
||||
</xs:complexType>
|
||||
</xs:element>
|
||||
</xs:schema>
|
||||
@ -10,6 +10,7 @@
|
||||
xmlns:shared="clr-namespace:Artemis.UI.Shared"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:controls1="clr-namespace:Artemis.UI.Shared.Controls"
|
||||
xmlns:utilities="clr-namespace:Artemis.UI.Shared.Utilities"
|
||||
mc:Ignorable="d"
|
||||
Background="{DynamicResource MaterialDesignPaper}"
|
||||
FontFamily="pack://application:,,,/MaterialDesignThemes.Wpf;component/Resources/Roboto/#Roboto"
|
||||
@ -22,13 +23,13 @@
|
||||
<converters:ColorGradientToGradientStopsConverter x:Key="ColorGradientToGradientStopsConverter" />
|
||||
<converters:SKColorToColorConverter x:Key="SKColorToColorConverter" />
|
||||
</UserControl.Resources>
|
||||
<Grid Margin="16">
|
||||
<Grid Margin="16">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<materialDesign:Card Grid.Row="0" Margin="15 15 15 7" >
|
||||
<materialDesign:Card Grid.Row="0" Margin="15 15 15 7">
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Margin="16">
|
||||
<materialDesign:PackIcon Kind="Crane" Width="80" Height="80" HorizontalAlignment="Center" />
|
||||
<TextBlock Style="{StaticResource MaterialDesignBody1TextBlock}" TextWrapping="Wrap"
|
||||
@ -47,7 +48,9 @@
|
||||
<TextBlock Margin="15 15 0 0">Gradient</TextBlock>
|
||||
<Separator Margin="15 5" />
|
||||
|
||||
<Rectangle x:Name="Preview" Width="440" Height="40" Margin="15 0">
|
||||
<Rectangle x:Name="Preview" Height="40" Margin="15 0"
|
||||
utilities:SizeObserver.Observe="True"
|
||||
utilities:SizeObserver.ObservedWidth="{Binding PreviewWidth, Mode=OneWayToSource}">
|
||||
<Rectangle.Fill>
|
||||
<LinearGradientBrush
|
||||
GradientStops="{Binding ColorGradient.Stops, Converter={StaticResource ColorGradientToGradientStopsConverter}}" />
|
||||
|
||||
@ -7,15 +7,14 @@ using System.Windows.Input;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.UI.Shared.Services.Dialog;
|
||||
using Artemis.UI.Shared.Utilities;
|
||||
using SkiaSharp;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Shared.Screens.GradientEditor
|
||||
{
|
||||
public class GradientEditorViewModel : DialogViewModelBase
|
||||
{
|
||||
private ColorStopViewModel _selectedColorStopViewModel;
|
||||
private readonly List<ColorGradientStop> _originalStops;
|
||||
private ColorStopViewModel _selectedColorStopViewModel;
|
||||
|
||||
public GradientEditorViewModel(ColorGradient colorGradient)
|
||||
{
|
||||
@ -24,8 +23,7 @@ namespace Artemis.UI.Shared.Screens.GradientEditor
|
||||
|
||||
_originalStops = ColorGradient.Stops.Select(s => new ColorGradientStop(s.Color, s.Position)).ToList();
|
||||
|
||||
foreach (var colorStop in ColorGradient.Stops.OrderBy(s => s.Position))
|
||||
ColorStopViewModels.Add(new ColorStopViewModel(this, colorStop));
|
||||
PropertyChanged += UpdateColorStopViewModels;
|
||||
}
|
||||
|
||||
public BindableCollection<ColorStopViewModel> ColorStopViewModels { get; set; }
|
||||
@ -43,8 +41,7 @@ namespace Artemis.UI.Shared.Screens.GradientEditor
|
||||
public bool HasSelectedColorStopViewModel => SelectedColorStopViewModel != null;
|
||||
|
||||
public ColorGradient ColorGradient { get; }
|
||||
// TODO: Find the width out from view
|
||||
public double PreviewWidth => 408;
|
||||
public double PreviewWidth { get; set; }
|
||||
|
||||
public void AddColorStop(object sender, MouseEventArgs e)
|
||||
{
|
||||
@ -99,5 +96,12 @@ namespace Artemis.UI.Shared.Screens.GradientEditor
|
||||
if (!Session.IsEnded)
|
||||
Session.Close(false);
|
||||
}
|
||||
|
||||
private void UpdateColorStopViewModels(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName != nameof(PreviewWidth)) return;
|
||||
foreach (var colorStop in ColorGradient.Stops.OrderBy(s => s.Position))
|
||||
ColorStopViewModels.Add(new ColorStopViewModel(this, colorStop));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,23 +1,16 @@
|
||||
using System.Collections.Generic;
|
||||
using Artemis.Core.Models.Profile;
|
||||
using Artemis.UI.Shared.Ninject.Factories;
|
||||
using Artemis.UI.Shared.Screens.GradientEditor;
|
||||
using Artemis.UI.Shared.Services.Interfaces;
|
||||
using LiteDB.Engine;
|
||||
using Ninject;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Shared.Services
|
||||
{
|
||||
public class GradientPickerService : IGradientPickerService
|
||||
{
|
||||
private readonly IGradientEditorVmFactory _gradientEditorVmFactory;
|
||||
private readonly IDialogService _dialogService;
|
||||
private readonly IWindowManager _windowManager;
|
||||
|
||||
public GradientPickerService(IGradientEditorVmFactory gradientEditorVmFactory, IDialogService dialogService)
|
||||
public GradientPickerService(IDialogService dialogService)
|
||||
{
|
||||
_gradientEditorVmFactory = gradientEditorVmFactory;
|
||||
_dialogService = dialogService;
|
||||
}
|
||||
|
||||
|
||||
@ -14,7 +14,10 @@ namespace Artemis.UI.Screens.Home
|
||||
{
|
||||
// Don't open anything but valid URIs
|
||||
if (Uri.IsWellFormedUriString(url, UriKind.RelativeOrAbsolute))
|
||||
Process.Start(url);
|
||||
{
|
||||
url = url.Replace("&", "^&");
|
||||
Process.Start(new ProcessStartInfo("cmd", $"/c start {url}") {CreateNoWindow = true});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -261,7 +261,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
||||
{
|
||||
// End time is the last keyframe + 10 sec
|
||||
var lastKeyFrame = PropertyTimeline.PropertyTrackViewModels.SelectMany(r => r.KeyframeViewModels).OrderByDescending(t => t.Keyframe.Position).FirstOrDefault();
|
||||
return lastKeyFrame?.Keyframe.Position.Add(new TimeSpan(0, 0, 0, 10)) ?? TimeSpan.FromSeconds(10);
|
||||
return lastKeyFrame?.Keyframe.Position.Add(new TimeSpan(0, 0, 0, 10)) ?? TimeSpan.MaxValue;
|
||||
}
|
||||
|
||||
private void CoreServiceOnFrameRendering(object sender, FrameRenderingEventArgs e)
|
||||
|
||||
@ -51,7 +51,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
|
||||
{
|
||||
}
|
||||
|
||||
private void LayerPropertyOnValueChanged(object? sender, EventArgs e)
|
||||
private void LayerPropertyOnValueChanged(object sender, EventArgs e)
|
||||
{
|
||||
Update();
|
||||
}
|
||||
|
||||
@ -10,6 +10,7 @@ using System.Windows.Media;
|
||||
using Artemis.Core.Models.Surface;
|
||||
using Artemis.Core.Plugins.Models;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.Core.Services.Interfaces;
|
||||
using Artemis.Core.Services.Storage.Interfaces;
|
||||
using Artemis.UI.Screens.Shared;
|
||||
using Artemis.UI.Screens.SurfaceEditor.Dialogs;
|
||||
@ -24,9 +25,11 @@ namespace Artemis.UI.Screens.SurfaceEditor
|
||||
private readonly IDeviceService _deviceService;
|
||||
private readonly IDialogService _dialogService;
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly IRgbService _rgbService;
|
||||
private readonly ISurfaceService _surfaceService;
|
||||
|
||||
public SurfaceEditorViewModel(ISurfaceService surfaceService, IDialogService dialogService, ISettingsService settingsService, IDeviceService deviceService)
|
||||
public SurfaceEditorViewModel(IRgbService rgbService, ISurfaceService surfaceService, IDialogService dialogService, ISettingsService settingsService,
|
||||
IDeviceService deviceService)
|
||||
{
|
||||
DisplayName = "Surface Editor";
|
||||
|
||||
@ -36,6 +39,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
|
||||
PanZoomViewModel = new PanZoomViewModel();
|
||||
Cursor = null;
|
||||
|
||||
_rgbService = rgbService;
|
||||
_surfaceService = surfaceService;
|
||||
_dialogService = dialogService;
|
||||
_settingsService = settingsService;
|
||||
@ -90,7 +94,9 @@ namespace Artemis.UI.Screens.SurfaceEditor
|
||||
{
|
||||
activeConfig = CreateSurfaceConfiguration("Default");
|
||||
configs.Add(activeConfig);
|
||||
_rgbService.UpdateTrigger.Stop();
|
||||
_surfaceService.SetActiveSurfaceConfiguration(activeConfig);
|
||||
_rgbService.UpdateTrigger.Start();
|
||||
}
|
||||
|
||||
Execute.PostToUIThread(() =>
|
||||
@ -134,7 +140,9 @@ namespace Artemis.UI.Screens.SurfaceEditor
|
||||
}
|
||||
});
|
||||
|
||||
_rgbService.UpdateTrigger.Stop();
|
||||
_surfaceService.SetActiveSurfaceConfiguration(SelectedSurface);
|
||||
_rgbService.UpdateTrigger.Start();
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
@ -195,7 +203,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
|
||||
deviceViewModel.Device.ZIndex = i + 1;
|
||||
}
|
||||
|
||||
_surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true);
|
||||
SafeUpdateSurfaceConfiguration();
|
||||
}
|
||||
|
||||
public void BringForward(SurfaceDeviceViewModel surfaceDeviceViewModel)
|
||||
@ -210,7 +218,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
|
||||
deviceViewModel.Device.ZIndex = i + 1;
|
||||
}
|
||||
|
||||
_surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true);
|
||||
SafeUpdateSurfaceConfiguration();
|
||||
}
|
||||
|
||||
public void SendToBack(SurfaceDeviceViewModel surfaceDeviceViewModel)
|
||||
@ -222,7 +230,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
|
||||
deviceViewModel.Device.ZIndex = i + 1;
|
||||
}
|
||||
|
||||
_surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true);
|
||||
SafeUpdateSurfaceConfiguration();
|
||||
}
|
||||
|
||||
public void SendBackward(SurfaceDeviceViewModel surfaceDeviceViewModel)
|
||||
@ -236,7 +244,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
|
||||
deviceViewModel.Device.ZIndex = i + 1;
|
||||
}
|
||||
|
||||
_surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true);
|
||||
SafeUpdateSurfaceConfiguration();
|
||||
}
|
||||
|
||||
public async Task ViewProperties(SurfaceDeviceViewModel surfaceDeviceViewModel)
|
||||
@ -247,7 +255,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
|
||||
});
|
||||
|
||||
if ((bool) madeChanges)
|
||||
_surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true);
|
||||
SafeUpdateSurfaceConfiguration();
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -343,8 +351,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
|
||||
}
|
||||
}
|
||||
else
|
||||
_surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true);
|
||||
|
||||
SafeUpdateSurfaceConfiguration();
|
||||
|
||||
_mouseDragStatus = MouseDragStatus.None;
|
||||
}
|
||||
@ -372,6 +379,13 @@ namespace Artemis.UI.Screens.SurfaceEditor
|
||||
device.UpdateMouseDrag(position);
|
||||
}
|
||||
|
||||
private void SafeUpdateSurfaceConfiguration()
|
||||
{
|
||||
_rgbService.UpdateTrigger.Stop();
|
||||
_surfaceService.UpdateSurfaceConfiguration(SelectedSurface, true);
|
||||
_rgbService.UpdateTrigger.Start();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Panning and zooming
|
||||
|
||||
@ -21,7 +21,7 @@
|
||||
</None>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="HidSharp" Version="2.0.1" />
|
||||
<PackageReference Include="HidSharp" Version="2.1.0" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\Artemis.Core\Artemis.Core.csproj">
|
||||
|
||||
@ -17,50 +17,27 @@ namespace Artemis.Plugins.LayerBrushes.Color
|
||||
|
||||
public ColorBrush(Layer layer, LayerBrushDescriptor descriptor) : base(layer, descriptor)
|
||||
{
|
||||
GradientTypeProperty = RegisterLayerProperty<GradientType>("Brush.GradientType", "Gradient type", "The type of color brush to draw");
|
||||
GradientTypeProperty = RegisterLayerProperty("Brush.GradientType", "Gradient type", "The type of color brush to draw", GradientType.Solid);
|
||||
GradientTypeProperty.CanUseKeyframes = false;
|
||||
|
||||
UpdateColorProperties();
|
||||
|
||||
Layer.RenderPropertiesUpdated += (sender, args) => CreateShader(_shaderBounds);
|
||||
Layer.RenderPropertiesUpdated += (sender, args) => CreateShader();
|
||||
GradientTypeProperty.ValueChanged += (sender, args) => UpdateColorProperties();
|
||||
}
|
||||
|
||||
private void UpdateColorProperties()
|
||||
{
|
||||
UnRegisterLayerProperty(ColorProperty);
|
||||
ColorProperty = null;
|
||||
UnRegisterLayerProperty(GradientProperty);
|
||||
GradientProperty = null;
|
||||
|
||||
if (GradientTypeProperty.Value == GradientType.Solid)
|
||||
{
|
||||
ColorProperty = RegisterLayerProperty("Brush.Color", "Color", "The color of the brush", new SKColor(255, 0, 0));
|
||||
ColorProperty.ValueChanged += (sender, args) => CreateShader(_shaderBounds);
|
||||
}
|
||||
else
|
||||
{
|
||||
GradientProperty = RegisterLayerProperty("Brush.Gradient", "Gradient", "The gradient of the brush", new ColorGradient());
|
||||
GradientProperty.Value.PropertyChanged += (sender, args) => CreateShader(_shaderBounds);
|
||||
|
||||
if (!GradientProperty.Value.Stops.Any())
|
||||
GradientProperty.Value.MakeFabulous();
|
||||
}
|
||||
|
||||
CreateShader(_shaderBounds);
|
||||
}
|
||||
|
||||
public LayerProperty<SKColor> ColorProperty { get; set; }
|
||||
public LayerProperty<ColorGradient> GradientProperty { get; set; }
|
||||
public LayerProperty<GradientType> GradientTypeProperty { get; set; }
|
||||
|
||||
public override void Update(double deltaTime)
|
||||
{
|
||||
// Only recreate the shader if the color changed
|
||||
if (ColorProperty != null && _color != ColorProperty.CurrentValue)
|
||||
// Only check if a solid is being drawn, because that can be changed by keyframes
|
||||
if (GradientTypeProperty.Value == GradientType.Solid && _color != ColorProperty.CurrentValue)
|
||||
{
|
||||
// If the color was changed since the last frame, recreate the shader
|
||||
_color = ColorProperty.CurrentValue;
|
||||
CreateShader(_shaderBounds);
|
||||
CreateShader();
|
||||
}
|
||||
|
||||
base.Update(deltaTime);
|
||||
@ -69,45 +46,69 @@ namespace Artemis.Plugins.LayerBrushes.Color
|
||||
public override void Render(SKCanvas canvas, SKImageInfo canvasInfo, SKPath path, SKPaint paint)
|
||||
{
|
||||
if (path.Bounds != _shaderBounds)
|
||||
CreateShader(path.Bounds);
|
||||
{
|
||||
_shaderBounds = path.Bounds;
|
||||
CreateShader();
|
||||
}
|
||||
|
||||
paint.Shader = _shader;
|
||||
canvas.DrawPath(path, paint);
|
||||
}
|
||||
|
||||
private void CreateShader(SKRect pathBounds)
|
||||
private void UpdateColorProperties()
|
||||
{
|
||||
var center = new SKPoint(pathBounds.MidX, pathBounds.MidY);
|
||||
SKShader shader;
|
||||
switch (GradientTypeProperty.CurrentValue)
|
||||
if (GradientTypeProperty.Value == GradientType.Solid)
|
||||
{
|
||||
case GradientType.Solid:
|
||||
shader = SKShader.CreateColor(_color);
|
||||
break;
|
||||
case GradientType.LinearGradient:
|
||||
shader = SKShader.CreateLinearGradient(new SKPoint(pathBounds.Left, pathBounds.Top), new SKPoint(pathBounds.Right, pathBounds.Bottom),
|
||||
GradientProperty.Value.GetColorsArray(),
|
||||
GradientProperty.Value.GetPositionsArray(), SKShaderTileMode.Repeat);
|
||||
break;
|
||||
case GradientType.RadialGradient:
|
||||
shader = SKShader.CreateRadialGradient(center, Math.Min(pathBounds.Width, pathBounds.Height),
|
||||
GradientProperty.Value.GetColorsArray(),
|
||||
GradientProperty.Value.GetPositionsArray(), SKShaderTileMode.Repeat);
|
||||
break;
|
||||
case GradientType.SweepGradient:
|
||||
shader = SKShader.CreateSweepGradient(center,
|
||||
GradientProperty.Value.GetColorsArray(),
|
||||
GradientProperty.Value.GetPositionsArray(), SKShaderTileMode.Clamp, 0, 360);
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
UnRegisterLayerProperty(GradientProperty);
|
||||
ColorProperty = RegisterLayerProperty("Brush.Color", "Color", "The color of the brush", new SKColor(255, 0, 0));
|
||||
ColorProperty.ValueChanged += (sender, args) => CreateShader();
|
||||
}
|
||||
else
|
||||
{
|
||||
UnRegisterLayerProperty(ColorProperty);
|
||||
GradientProperty = RegisterLayerProperty("Brush.Gradient", "Gradient", "The gradient of the brush", new ColorGradient());
|
||||
GradientProperty.CanUseKeyframes = false;
|
||||
GradientProperty.Value.PropertyChanged += (sender, args) => CreateShader();
|
||||
|
||||
if (!GradientProperty.Value.Stops.Any())
|
||||
GradientProperty.Value.MakeFabulous();
|
||||
}
|
||||
|
||||
CreateShader();
|
||||
}
|
||||
|
||||
private void CreateShader()
|
||||
{
|
||||
var center = new SKPoint(_shaderBounds.MidX, _shaderBounds.MidY);
|
||||
var shader = GradientTypeProperty.CurrentValue switch
|
||||
{
|
||||
GradientType.Solid => SKShader.CreateColor(_color),
|
||||
GradientType.LinearGradient => SKShader.CreateLinearGradient(
|
||||
new SKPoint(_shaderBounds.Left, _shaderBounds.Top),
|
||||
new SKPoint(_shaderBounds.Right, _shaderBounds.Bottom),
|
||||
GradientProperty.Value.GetColorsArray(),
|
||||
GradientProperty.Value.GetPositionsArray(),
|
||||
SKShaderTileMode.Repeat),
|
||||
GradientType.RadialGradient => SKShader.CreateRadialGradient(
|
||||
center,
|
||||
Math.Min(_shaderBounds.Width, _shaderBounds.Height),
|
||||
GradientProperty.Value.GetColorsArray(),
|
||||
GradientProperty.Value.GetPositionsArray(),
|
||||
SKShaderTileMode.Repeat),
|
||||
GradientType.SweepGradient => SKShader.CreateSweepGradient(
|
||||
center,
|
||||
GradientProperty.Value.GetColorsArray(),
|
||||
GradientProperty.Value.GetPositionsArray(),
|
||||
SKShaderTileMode.Clamp,
|
||||
0,
|
||||
360),
|
||||
_ => throw new ArgumentOutOfRangeException()
|
||||
};
|
||||
|
||||
var oldShader = _shader;
|
||||
var oldPaint = _paint;
|
||||
_shader = shader;
|
||||
_paint = new SKPaint {Shader = _shader, FilterQuality = SKFilterQuality.Low};
|
||||
_shaderBounds = pathBounds;
|
||||
oldShader?.Dispose();
|
||||
oldPaint?.Dispose();
|
||||
}
|
||||
|
||||
@ -62,21 +62,20 @@ namespace Artemis.Plugins.LayerBrushes.Noise
|
||||
public LayerProperty<SKPoint> ScrollSpeedProperty { get; set; }
|
||||
public LayerProperty<float> AnimationSpeedProperty { get; set; }
|
||||
|
||||
|
||||
private void UpdateColorProperties()
|
||||
{
|
||||
UnRegisterLayerProperty(MainColorProperty);
|
||||
UnRegisterLayerProperty(SecondaryColorProperty);
|
||||
UnRegisterLayerProperty(GradientColorProperty);
|
||||
if (GradientColorProperty != null)
|
||||
GradientColorProperty.Value.PropertyChanged -= CreateColorMap;
|
||||
if (ColorTypeProperty.Value == ColorMappingType.Simple)
|
||||
{
|
||||
UnRegisterLayerProperty(GradientColorProperty);
|
||||
MainColorProperty = RegisterLayerProperty("Brush.MainColor", "Main color", "The main color of the noise", new SKColor(255, 0, 0));
|
||||
SecondaryColorProperty = RegisterLayerProperty("Brush.SecondaryColor", "Secondary color", "The secondary color of the noise", new SKColor(0, 0, 255));
|
||||
}
|
||||
else
|
||||
{
|
||||
UnRegisterLayerProperty(MainColorProperty);
|
||||
UnRegisterLayerProperty(SecondaryColorProperty);
|
||||
GradientColorProperty = RegisterLayerProperty("Brush.GradientColor", "Noise gradient map", "The gradient the noise will map it's value to", new ColorGradient());
|
||||
if (!GradientColorProperty.Value.Stops.Any())
|
||||
GradientColorProperty.Value.MakeFabulous();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user