1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2026-01-01 10:13:30 +00:00

UI - Added device visualizer and rudementary panzoom

This commit is contained in:
Robert 2021-10-24 15:40:31 +02:00
parent 6bbe6b6bbe
commit ff55168f23
20 changed files with 472 additions and 232 deletions

View File

@ -362,7 +362,7 @@ namespace Artemis.Core.Services
{ {
// Load the enabled state and if not found, default to true // Load the enabled state and if not found, default to true
PluginFeatureEntity featureEntity = plugin.Entity.Features.FirstOrDefault(i => i.Type == featureType.FullName) ?? PluginFeatureEntity featureEntity = plugin.Entity.Features.FirstOrDefault(i => i.Type == featureType.FullName) ??
new PluginFeatureEntity {IsEnabled = plugin.Info.AutoEnableFeatures, Type = featureType.FullName!}; new PluginFeatureEntity {IsEnabled = true, Type = featureType.FullName!};
plugin.AddFeature(new PluginFeatureInfo(plugin, featureType, featureEntity, (PluginFeatureAttribute?) Attribute.GetCustomAttribute(featureType, typeof(PluginFeatureAttribute)))); plugin.AddFeature(new PluginFeatureInfo(plugin, featureType, featureEntity, (PluginFeatureAttribute?) Attribute.GetCustomAttribute(featureType, typeof(PluginFeatureAttribute))));
} }

View File

@ -7,11 +7,11 @@
<StartupObject /> <StartupObject />
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.7" /> <PackageReference Include="Avalonia" Version="0.10.8" />
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.7.2" /> <PackageReference Include="Avalonia.Svg.Skia" Version="0.10.8.3" />
<PackageReference Include="Avalonia.Xaml.Behaviors" Version="0.10.7.1" /> <PackageReference Include="Avalonia.Xaml.Behaviors" Version="0.10.8" />
<PackageReference Include="Avalonia.Xaml.Interactions" Version="0.10.7.1" /> <PackageReference Include="Avalonia.Xaml.Interactions" Version="0.10.8" />
<PackageReference Include="Avalonia.Xaml.Interactivity" Version="0.10.7.1" /> <PackageReference Include="Avalonia.Xaml.Interactivity" Version="0.10.8" />
<PackageReference Include="Material.Icons.Avalonia" Version="1.0.2" /> <PackageReference Include="Material.Icons.Avalonia" Version="1.0.2" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -12,7 +12,10 @@ using Avalonia.Input;
using Avalonia.LogicalTree; using Avalonia.LogicalTree;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Media.Imaging; using Avalonia.Media.Imaging;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Threading; using Avalonia.Threading;
using Avalonia.Visuals.Media.Imaging;
namespace Artemis.UI.Avalonia.Shared.Controls namespace Artemis.UI.Avalonia.Shared.Controls
{ {
@ -21,10 +24,11 @@ namespace Artemis.UI.Avalonia.Shared.Controls
/// </summary> /// </summary>
public class DeviceVisualizer : Control public class DeviceVisualizer : Control
{ {
private readonly DispatcherTimer _timer; private const double UpdateFrameRate = 25.0;
private readonly List<DeviceVisualizerLed> _deviceVisualizerLeds; private readonly List<DeviceVisualizerLed> _deviceVisualizerLeds;
private readonly DispatcherTimer _timer;
private Bitmap? _deviceImage; private RenderTargetBitmap? _deviceImage;
private List<DeviceVisualizerLed>? _dimmedLeds; private List<DeviceVisualizerLed>? _dimmedLeds;
private List<DeviceVisualizerLed>? _highlightedLeds; private List<DeviceVisualizerLed>? _highlightedLeds;
private ArtemisDevice? _oldDevice; private ArtemisDevice? _oldDevice;
@ -32,8 +36,7 @@ namespace Artemis.UI.Avalonia.Shared.Controls
/// <inheritdoc /> /// <inheritdoc />
public DeviceVisualizer() public DeviceVisualizer()
{ {
// Run an update timer at 25 fps _timer = new DispatcherTimer(DispatcherPriority.Render) {Interval = TimeSpan.FromMilliseconds(1000.0 / UpdateFrameRate)};
_timer = new DispatcherTimer(DispatcherPriority.Render) {Interval = TimeSpan.FromMilliseconds(40)};
_deviceVisualizerLeds = new List<DeviceVisualizerLed>(); _deviceVisualizerLeds = new List<DeviceVisualizerLed>();
PointerReleased += OnPointerReleased; PointerReleased += OnPointerReleased;
@ -45,27 +48,35 @@ namespace Artemis.UI.Avalonia.Shared.Controls
if (Device == null) if (Device == null)
return; return;
List<DrawingContext.PushedState> pushes = new(4);
// Determine the scale required to fit the desired size of the control // Determine the scale required to fit the desired size of the control
Rect measureSize = MeasureDevice(); Rect measureSize = MeasureDevice();
double scale = Math.Min(Bounds.Width / measureSize.Width, Bounds.Height / measureSize.Height); double scale = Math.Min(Bounds.Width / measureSize.Width, Bounds.Height / measureSize.Height);
// Scale the visualization in the desired bounding box // Scale the visualization in the desired bounding box
if (Bounds.Width > 0 && Bounds.Height > 0) if (Bounds.Width > 0 && Bounds.Height > 0)
drawingContext.PushPostTransform(Matrix.CreateScale(scale, scale)); pushes.Add(drawingContext.PushPostTransform(Matrix.CreateScale(scale, scale)));
// Apply device rotation // Apply device rotation
drawingContext.PushPostTransform(Matrix.CreateTranslation(0 - measureSize.Left, 0 - measureSize.Top)); pushes.Add(drawingContext.PushPostTransform(Matrix.CreateTranslation(0 - measureSize.Left, 0 - measureSize.Top)));
drawingContext.PushPostTransform(Matrix.CreateRotation(Device.Rotation)); pushes.Add(drawingContext.PushPostTransform(Matrix.CreateRotation(Device.Rotation)));
// Apply device scale // Apply device scale
drawingContext.PushPostTransform(Matrix.CreateScale(Device.Scale, Device.Scale)); pushes.Add(drawingContext.PushPostTransform(Matrix.CreateScale(Device.Scale, Device.Scale)));
// Render device and LED images // Render device and LED images
if (_deviceImage != null) if (_deviceImage != null)
drawingContext.DrawImage(_deviceImage, new Rect(0, 0, Device.RgbDevice.Size.Width, Device.RgbDevice.Size.Height)); drawingContext.DrawImage(_deviceImage, new Rect(0, 0, Device.RgbDevice.ActualSize.Width, Device.RgbDevice.ActualSize.Height));
foreach (DeviceVisualizerLed deviceVisualizerLed in _deviceVisualizerLeds) foreach (DeviceVisualizerLed deviceVisualizerLed in _deviceVisualizerLeds)
deviceVisualizerLed.RenderImage(drawingContext); deviceVisualizerLed.RenderGeometry(drawingContext);
for (int index = pushes.Count - 1; index >= 0; index--)
{
DrawingContext.PushedState pushedState = pushes[index];
pushedState.Dispose();
}
} }
/// <summary> /// <summary>
@ -73,6 +84,13 @@ namespace Artemis.UI.Avalonia.Shared.Controls
/// </summary> /// </summary>
public event EventHandler<LedClickedEventArgs>? LedClicked; public event EventHandler<LedClickedEventArgs>? LedClicked;
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
_deviceImage?.Dispose();
_deviceImage = null;
base.OnDetachedFromVisualTree(e);
}
/// <summary> /// <summary>
/// Invokes the <see cref="LedClicked" /> event /// Invokes the <see cref="LedClicked" /> event
/// </summary> /// </summary>
@ -142,7 +160,13 @@ namespace Artemis.UI.Avalonia.Shared.Controls
/// Gets or sets the <see cref="ArtemisDevice" /> to display /// Gets or sets the <see cref="ArtemisDevice" /> to display
/// </summary> /// </summary>
public static readonly StyledProperty<ArtemisDevice?> DeviceProperty = public static readonly StyledProperty<ArtemisDevice?> DeviceProperty =
AvaloniaProperty.Register<DeviceVisualizer, ArtemisDevice?>(nameof(Device)); AvaloniaProperty.Register<DeviceVisualizer, ArtemisDevice?>(nameof(Device), notifying: DeviceUpdated);
private static void DeviceUpdated(IAvaloniaObject sender, bool before)
{
if (!before)
((DeviceVisualizer) sender).SetupForDevice();
}
/// <summary> /// <summary>
/// Gets or sets the <see cref="ArtemisDevice" /> to display /// Gets or sets the <see cref="ArtemisDevice" /> to display
@ -225,14 +249,32 @@ namespace Artemis.UI.Avalonia.Shared.Controls
Device.DeviceUpdated += DeviceUpdated; Device.DeviceUpdated += DeviceUpdated;
UpdateTransform(); UpdateTransform();
// Load the device main image
if (Device.Layout?.Image != null && File.Exists(Device.Layout.Image.LocalPath))
_deviceImage = new Bitmap(Device.Layout.Image.AbsolutePath);
// Create all the LEDs // Create all the LEDs
foreach (ArtemisLed artemisLed in Device.Leds) foreach (ArtemisLed artemisLed in Device.Leds)
_deviceVisualizerLeds.Add(new DeviceVisualizerLed(artemisLed)); _deviceVisualizerLeds.Add(new DeviceVisualizerLed(artemisLed));
// Load the device main image
if (Device.Layout?.Image != null && File.Exists(Device.Layout.Image.LocalPath))
{
try
{
// Create a bitmap that'll be used to render the device and LED images just once
RenderTargetBitmap renderTargetBitmap = new(new PixelSize((int) Device.RgbDevice.Size.Width * 4, (int) Device.RgbDevice.Size.Height * 4));
using IDrawingContextImpl context = renderTargetBitmap.CreateDrawingContext(new ImmediateRenderer(this));
using Bitmap bitmap = new(Device.Layout.Image.LocalPath);
context.DrawBitmap(bitmap.PlatformImpl, 1, new Rect(bitmap.Size), new Rect(renderTargetBitmap.Size), BitmapInterpolationMode.HighQuality);
foreach (DeviceVisualizerLed deviceVisualizerLed in _deviceVisualizerLeds)
deviceVisualizerLed.DrawBitmap(context);
_deviceImage = renderTargetBitmap;
}
catch
{
// ignored
}
}
InvalidateMeasure(); InvalidateMeasure();
} }

View File

@ -4,6 +4,8 @@ using Artemis.Core;
using Avalonia; using Avalonia;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Media.Imaging; using Avalonia.Media.Imaging;
using Avalonia.Platform;
using Avalonia.Visuals.Media.Imaging;
using RGB.NET.Core; using RGB.NET.Core;
using Color = Avalonia.Media.Color; using Color = Avalonia.Media.Color;
using Point = Avalonia.Point; using Point = Avalonia.Point;
@ -13,6 +15,9 @@ namespace Artemis.UI.Avalonia.Shared.Controls
{ {
internal class DeviceVisualizerLed internal class DeviceVisualizerLed
{ {
private readonly SolidColorBrush _penBrush;
private readonly SolidColorBrush _fillBrush;
private readonly Pen _pen;
private const byte Dimmed = 100; private const byte Dimmed = 100;
private const byte NonDimmed = 255; private const byte NonDimmed = 255;
@ -26,46 +31,54 @@ namespace Artemis.UI.Avalonia.Shared.Controls
Led.RgbLed.Size.Height Led.RgbLed.Size.Height
); );
if (Led.Layout?.Image != null && File.Exists(Led.Layout.Image.LocalPath)) _fillBrush = new SolidColorBrush();
LedImage = new Bitmap(Led.Layout.Image.AbsolutePath); _penBrush = new SolidColorBrush();
_pen = new Pen(_penBrush) {LineJoin = PenLineJoin.Round};
CreateLedGeometry(); CreateLedGeometry();
} }
public ArtemisLed Led { get; } public ArtemisLed Led { get; }
public Rect LedRect { get; set; } public Rect LedRect { get; set; }
public Bitmap? LedImage { get; set; }
public Geometry? DisplayGeometry { get; private set; } public Geometry? DisplayGeometry { get; private set; }
public void RenderImage(DrawingContext drawingContext) public void DrawBitmap(IDrawingContextImpl drawingContext)
{ {
if (LedImage == null) if (Led.Layout?.Image == null || !File.Exists(Led.Layout.Image.LocalPath))
return; return;
drawingContext.DrawImage(LedImage, LedRect); try
{
using Bitmap bitmap = new(Led.Layout.Image.LocalPath);
drawingContext.DrawBitmap(
bitmap.PlatformImpl,
1,
new Rect(bitmap.Size),
new Rect(Led.RgbLed.Location.X * 4, Led.RgbLed.Location.Y * 4, Led.RgbLed.Size.Width * 4, Led.RgbLed.Size.Height * 4),
BitmapInterpolationMode.HighQuality
);
}
catch
{
// ignored
}
}
public void RenderGeometry(DrawingContext drawingContext)
{
byte r = Led.RgbLed.Color.GetR(); byte r = Led.RgbLed.Color.GetR();
byte g = Led.RgbLed.Color.GetG(); byte g = Led.RgbLed.Color.GetG();
byte b = Led.RgbLed.Color.GetB(); byte b = Led.RgbLed.Color.GetB();
SolidColorBrush fillBrush = new(new Color(100, r, g, b)); _fillBrush.Color = new Color(100, r, g, b);
SolidColorBrush penBrush = new(new Color(255, r, g, b)); _penBrush.Color = new Color(255, r, g, b);
// Create transparent pixels covering the entire LedRect so the image size matched the LedRect size
// drawingContext.DrawRectangle(new SolidColorBrush(Colors.Transparent), new Pen(new SolidColorBrush(Colors.Transparent), 1), LedRect);
// Translate to the top-left of the LedRect
using DrawingContext.PushedState push = drawingContext.PushPostTransform(Matrix.CreateTranslation(LedRect.X, LedRect.Y));
// Render the LED geometry // Render the LED geometry
drawingContext.DrawGeometry(fillBrush, new Pen(penBrush) {LineJoin = PenLineJoin.Round}, DisplayGeometry); drawingContext.DrawGeometry(_fillBrush, _pen, DisplayGeometry);
} }
public bool HitTest(Point position) public bool HitTest(Point position)
{ {
if (DisplayGeometry == null) return DisplayGeometry != null && DisplayGeometry.FillContains(position);
return false;
Geometry translatedGeometry = DisplayGeometry.Clone();
translatedGeometry.Transform = new TranslateTransform(Led.RgbLed.Location.X, Led.RgbLed.Location.Y);
return translatedGeometry.FillContains(position);
} }
private void CreateLedGeometry() private void CreateLedGeometry()
@ -98,26 +111,17 @@ namespace Artemis.UI.Avalonia.Shared.Controls
private void CreateRectangleGeometry() private void CreateRectangleGeometry()
{ {
DisplayGeometry = new RectangleGeometry(new Rect(0.5, 0.5, Led.RgbLed.Size.Width - 1, Led.RgbLed.Size.Height - 1)); DisplayGeometry = new RectangleGeometry(new Rect(Led.RgbLed.Location.X + 0.5, Led.RgbLed.Location.Y + 0.5, Led.RgbLed.Size.Width - 1, Led.RgbLed.Size.Height - 1));
} }
private void CreateCircleGeometry() private void CreateCircleGeometry()
{ {
DisplayGeometry = new EllipseGeometry(new Rect(0.5, 0.5, Led.RgbLed.Size.Width - 1, Led.RgbLed.Size.Height - 1)); DisplayGeometry = new EllipseGeometry(new Rect(Led.RgbLed.Location.X + 0.5, Led.RgbLed.Location.Y + 0.5, Led.RgbLed.Size.Width - 1, Led.RgbLed.Size.Height - 1));
} }
private void CreateKeyCapGeometry() private void CreateKeyCapGeometry()
{ {
PathGeometry path = PathGeometry.Parse($"M1,1" + DisplayGeometry = new RectangleGeometry(new Rect(Led.RgbLed.Location.X + 1, Led.RgbLed.Location.Y + 1, Led.RgbLed.Size.Width - 2, Led.RgbLed.Size.Height - 2));
$"h{Led.RgbLed.Size.Width - 2} a10," +
$"10 0 0 1 10," +
$"10 v{Led.RgbLed.Size.Height - 2} a10," +
$"10 0 0 1 -10," +
$"10 h-{Led.RgbLed.Size.Width - 2} a10," +
$"10 0 0 1 -10," +
$"-10 v-{Led.RgbLed.Size.Height - 2} a10," +
$"10 0 0 1 10,-10 z");
DisplayGeometry = path;
} }
private void CreateCustomGeometry(double deflateAmount) private void CreateCustomGeometry(double deflateAmount)
@ -128,27 +132,15 @@ namespace Artemis.UI.Avalonia.Shared.Controls
double height = Led.RgbLed.Size.Height - deflateAmount; double height = Led.RgbLed.Size.Height - deflateAmount;
Geometry geometry = Geometry.Parse(Led.RgbLed.ShapeData); Geometry geometry = Geometry.Parse(Led.RgbLed.ShapeData);
geometry.Transform = new ScaleTransform(width, height); geometry.Transform = new TransformGroup
geometry = geometry.Clone(); {
geometry.Transform = new TranslateTransform(deflateAmount / 2, deflateAmount / 2); Children = new Transforms
DisplayGeometry = geometry.Clone(); {
new ScaleTransform(width, height),
// TODO: Figure out wtf was going on here new TranslateTransform(Led.RgbLed.Location.X + deflateAmount / 2, Led.RgbLed.Location.Y + deflateAmount / 2)
// if (DisplayGeometry.Bounds.Width > width) }
// { };
// DisplayGeometry = Geometry.Combine(Geometry.Empty, DisplayGeometry, GeometryCombineMode.Union, new TransformGroup DisplayGeometry = geometry;
// {
// Children = new TransformCollection {new ScaleTransform(width / DisplayGeometry.Bounds.Width, 1)}
// });
// }
//
// if (DisplayGeometry.Bounds.Height > height)
// {
// DisplayGeometry = Geometry.Combine(Geometry.Empty, DisplayGeometry, GeometryCombineMode.Union, new TransformGroup
// {
// Children = new TransformCollection {new ScaleTransform(1, height / DisplayGeometry.Bounds.Height)}
// });
// }
} }
catch (Exception) catch (Exception)
{ {

View File

@ -0,0 +1,22 @@
using System;
namespace Artemis.UI.Avalonia.Shared.Exceptions
{
/// <summary>
/// Represents errors that occur within the Artemis Shared UI library
/// </summary>
public class ArtemisSharedUIException : Exception
{
internal ArtemisSharedUIException()
{
}
internal ArtemisSharedUIException(string message) : base(message)
{
}
internal ArtemisSharedUIException(string message, Exception inner) : base(message, inner)
{
}
}
}

View File

@ -0,0 +1,31 @@
using System;
using Artemis.UI.Avalonia.Shared.Services.Interfaces;
using Ninject.Extensions.Conventions;
using Ninject.Modules;
namespace Artemis.UI.Avalonia.Shared.Ninject
{
/// <summary>
/// The main <see cref="NinjectModule" /> of the Artemis Shared UI toolkit that binds all services
/// </summary>
public class SharedUIModule : NinjectModule
{
/// <inheritdoc />
public override void Load()
{
if (Kernel == null)
throw new ArgumentNullException("Kernel shouldn't be null here.");
// Bind all shared UI services as singletons
Kernel.Bind(x =>
{
x.FromAssemblyContaining<IArtemisSharedUIService>()
.IncludingNonPublicTypes()
.SelectAllClasses()
.InheritedFrom<IArtemisSharedUIService>()
.BindAllInterfaces()
.Configure(c => c.InSingletonScope());
});
}
}
}

View File

@ -0,0 +1,20 @@
namespace Artemis.UI.Avalonia.Shared.Services.Interfaces
{
public interface IWindowService : IArtemisSharedUIService
{
T ShowWindow<T>();
/// <summary>
/// Given a ViewModel, show its corresponding View as a window
/// </summary>
/// <param name="viewModel">ViewModel to show the View for</param>
void ShowWindow(object viewModel);
/// <summary>
/// Given a ViewModel, show its corresponding View as a Dialog
/// </summary>
/// <param name="viewModel">ViewModel to show the View for</param>
/// <returns>DialogResult of the View</returns>
bool? ShowDialog(object viewModel);
}
}

View File

@ -0,0 +1,52 @@
using System;
using Artemis.UI.Avalonia.Shared.Exceptions;
using Artemis.UI.Avalonia.Shared.Services.Interfaces;
using Avalonia.Controls;
using Ninject;
namespace Artemis.UI.Avalonia.Shared.Services
{
internal class WindowService : IWindowService
{
private readonly IKernel _kernel;
public WindowService(IKernel kernel)
{
_kernel = kernel;
}
#region Implementation of IWindowService
/// <inheritdoc />
public T ShowWindow<T>()
{
T viewModel = _kernel.Get<T>()!;
ShowWindow(viewModel);
return viewModel;
}
/// <inheritdoc />
public void ShowWindow(object viewModel)
{
string name = viewModel.GetType().FullName!.Split('`')[0].Replace("ViewModel", "View");
Type? type = viewModel.GetType().Assembly.GetType(name);
if (type == null)
throw new ArtemisSharedUIException($"Failed to find a window named {name}.");
if (!type.IsAssignableTo(typeof(Window)))
throw new ArtemisSharedUIException($"Type {name} is not a window.");
Window window = (Window) Activator.CreateInstance(type)!;
window.DataContext = viewModel;
window.Show();
}
/// <inheritdoc />
public bool? ShowDialog(object viewModel)
{
throw new NotImplementedException();
}
#endregion
}
}

View File

@ -4,11 +4,11 @@
".NETCoreApp,Version=v5.0": { ".NETCoreApp,Version=v5.0": {
"Avalonia": { "Avalonia": {
"type": "Direct", "type": "Direct",
"requested": "[0.10.7, )", "requested": "[0.10.8, )",
"resolved": "0.10.7", "resolved": "0.10.8",
"contentHash": "savkS5LlA3bGAXvP9RfPRLRjeGp7XXExNRNhM4BaxCHGsopsWOpRt0nNI6X7FrC9Ous3h+k+gKQu8kc+AZHj8A==", "contentHash": "/m31yPKz7iqV5thzlLGi8ERgiTV+FYl7NePafwDpN41aLwz8u4rrTviWm9QJH78cwj8tGCf9Pqp8Nm0fckfAZA==",
"dependencies": { "dependencies": {
"Avalonia.Remote.Protocol": "0.10.7", "Avalonia.Remote.Protocol": "0.10.8",
"JetBrains.Annotations": "10.3.0", "JetBrains.Annotations": "10.3.0",
"System.ComponentModel.Annotations": "4.5.0", "System.ComponentModel.Annotations": "4.5.0",
"System.Memory": "4.5.3", "System.Memory": "4.5.3",
@ -19,44 +19,44 @@
}, },
"Avalonia.Svg.Skia": { "Avalonia.Svg.Skia": {
"type": "Direct", "type": "Direct",
"requested": "[0.10.7.2, )", "requested": "[0.10.8.3, )",
"resolved": "0.10.7.2", "resolved": "0.10.8.3",
"contentHash": "a5zt8IwrLeG+2hQ+Hs7/2zjPH5vujFQvcmOOWikM9iktm6Vjejqj8h1ssZK3n4TfGmIkq2AtbQcTBAC1nqFP6A==", "contentHash": "w7RYf+8+gOI3uVZZJ59S0EP49LVsyr1jpnZQzVFQqKa3y/c/i2jT/EUoKOeaqPMhFIsQZyEF4iluqoo6aZ05Tw==",
"dependencies": { "dependencies": {
"Avalonia": "0.10.7", "Avalonia": "0.10.8",
"Avalonia.Skia": "0.10.7", "Avalonia.Skia": "0.10.8",
"SkiaSharp": "2.80.2", "SkiaSharp": "2.80.2",
"Svg.Skia": "0.5.7.2" "Svg.Skia": "0.5.8.3"
} }
}, },
"Avalonia.Xaml.Behaviors": { "Avalonia.Xaml.Behaviors": {
"type": "Direct", "type": "Direct",
"requested": "[0.10.7.1, )", "requested": "[0.10.8, )",
"resolved": "0.10.7.1", "resolved": "0.10.8",
"contentHash": "Ef5PCejEA6F25GadMwVVqATeWrZ7XFouerQvbeIpH2FOD8iS8Vg8vEJFGkHLv1N6HHUF2nZUb01csfs6bOy4Jg==", "contentHash": "3nkh36Qp9fK8/Fh/nxqaVMlAzj8iuH5RUcs2rTrcyqn1WPJTslwQrxk+HDMYneuBE9+Oi31ZWiZImEM9kEQN7w==",
"dependencies": { "dependencies": {
"Avalonia": "0.10.7", "Avalonia": "0.10.8",
"Avalonia.Xaml.Interactions": "0.10.7.1", "Avalonia.Xaml.Interactions": "0.10.8",
"Avalonia.Xaml.Interactivity": "0.10.7.1" "Avalonia.Xaml.Interactivity": "0.10.8"
} }
}, },
"Avalonia.Xaml.Interactions": { "Avalonia.Xaml.Interactions": {
"type": "Direct", "type": "Direct",
"requested": "[0.10.7.1, )", "requested": "[0.10.8, )",
"resolved": "0.10.7.1", "resolved": "0.10.8",
"contentHash": "ZFgGnjUKbZofMAriGn8xPW/3rt1iww2pUTtOQW8+8YQDtFBjZtq2LaiE0ExX9HgPqgrFM8LYwGcf8SsYZb1pNg==", "contentHash": "3pXshQ1pNr+ul7Q2Sn6jjWMHOgRM2uKsUCh95QD2O2wpjgxpRpqiNEy1xPv2+bX2FMWTQIaOdQ8eNM8EunAWMg==",
"dependencies": { "dependencies": {
"Avalonia": "0.10.7", "Avalonia": "0.10.8",
"Avalonia.Xaml.Interactivity": "0.10.7.1" "Avalonia.Xaml.Interactivity": "0.10.8"
} }
}, },
"Avalonia.Xaml.Interactivity": { "Avalonia.Xaml.Interactivity": {
"type": "Direct", "type": "Direct",
"requested": "[0.10.7.1, )", "requested": "[0.10.8, )",
"resolved": "0.10.7.1", "resolved": "0.10.8",
"contentHash": "vLYy2lRISft55wwU7gKTXdBfbdkas1u/bznO05IYCFQzwVRo5ktSs1U1fy6ZzrK5z9Lq/e05GM7Q123n4Dfpow==", "contentHash": "ObL26GjME53R3KRkGB97dIB3jwGzyNS/7Www8fZjCEbK4AnjXVgzyw7gkHNsHD9DEZArovvURQI0qvvz3tb24g==",
"dependencies": { "dependencies": {
"Avalonia": "0.10.7" "Avalonia": "0.10.8"
} }
}, },
"Material.Icons.Avalonia": { "Material.Icons.Avalonia": {
@ -71,15 +71,15 @@
}, },
"Avalonia.Remote.Protocol": { "Avalonia.Remote.Protocol": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.10.7", "resolved": "0.10.8",
"contentHash": "w8Le0g2StgD1/32mEPYzP0MhMfDyeHvATHFV3IYA2oQTiPoicjUy3To+PuwAB9T9SSi9DtkLhwazlWZOqQGuAw==" "contentHash": "flpM/ZF2vkzbHbmSKdq6qWxy/bw/2C1k3Oc73ewlUdwBUWMov6mX99yUWNNI26oYrgD2fpaRhHMukcoSCYqbuQ=="
}, },
"Avalonia.Skia": { "Avalonia.Skia": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.10.7", "resolved": "0.10.8",
"contentHash": "dV6WXLk5ziYhnDAwf/fagoVRPTBN4LvFt1BMgikvVKCrkWlmtnQQ/Rav9ESJ13c887XpWMGcERYne3vzeLP6MA==", "contentHash": "FsCeOhzDCE4GJnqBGzH/54tqsn0j39Xpkdf3TmuC0MZzjW82Me3GUGeO25E9zs7sEMtX0MKWocmBx6c6ADcGXA==",
"dependencies": { "dependencies": {
"Avalonia": "0.10.7", "Avalonia": "0.10.8",
"HarfBuzzSharp": "2.6.1.7", "HarfBuzzSharp": "2.6.1.7",
"HarfBuzzSharp.NativeAssets.Linux": "2.6.1.7", "HarfBuzzSharp.NativeAssets.Linux": "2.6.1.7",
"SkiaSharp": "2.80.2", "SkiaSharp": "2.80.2",
@ -438,8 +438,8 @@
}, },
"ShimSkiaSharp": { "ShimSkiaSharp": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.5.7.2", "resolved": "0.5.8.3",
"contentHash": "+KFniLMpqei3Hj1T586ZY/ZDZXXyl6NFLTXvSZ5LvEi96KIcEgbFCuSsNCVfTmnKQaLCn4Gn+KHjqroCJe2FFA==" "contentHash": "BWwwsIlYUFF0DUc8Pa9xONIXVDvEL9pOYc9YmWilpHrWC37dcK+H4+tfuxztZxtfJx559HGn+6iZmMDjfFoOxA=="
}, },
"SkiaSharp": { "SkiaSharp": {
"type": "Transitive", "type": "Transitive",
@ -468,8 +468,8 @@
}, },
"Svg.Custom": { "Svg.Custom": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.5.7.2", "resolved": "0.5.8.3",
"contentHash": "BLb8ViaXEWWsYvbxtGj+ITNO1CpZEszWT8sE5Xa1qkeoniIENog5PEKGTc5mAJ8MhFc4GYO33Vo9duH0KzizNQ==", "contentHash": "6FnbI4T3uCNN7DYJpfPFa4caTTJzp4YbhU3J4c/syX7wQNSeQ/1u7JZZ+dGgrRUauiWP8VsiCLKP8qinc5xI5w==",
"dependencies": { "dependencies": {
"Fizzler": "1.2.0", "Fizzler": "1.2.0",
"System.Drawing.Common": "5.0.0", "System.Drawing.Common": "5.0.0",
@ -480,22 +480,22 @@
}, },
"Svg.Model": { "Svg.Model": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.5.7.2", "resolved": "0.5.8.3",
"contentHash": "txH95pxkg75s2LBcONXFCmrpYp5flUC5aF1DaLwTtt33dv9WvOQQlxnasNyb0CN7t0yaXpX8CZoo+SU9u1E/eA==", "contentHash": "F/rimPwV5KF64P8oofXGMwOZ0T7b3z1A9OiC4mv5OdSpLpMpUxpSwGLAOkJ5DFqQgXqVjKKLhPdjIjQBwy0AjA==",
"dependencies": { "dependencies": {
"ShimSkiaSharp": "0.5.7.2", "ShimSkiaSharp": "0.5.8.3",
"Svg.Custom": "0.5.7.2" "Svg.Custom": "0.5.8.3"
} }
}, },
"Svg.Skia": { "Svg.Skia": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.5.7.2", "resolved": "0.5.8.3",
"contentHash": "QknpGmwSsns+/05W4efAuPvd77AsimuN5bAGTHGzHQPkPY/htgfXPm2YKywsEIpbXvUiTCfvzaSxSlkYHK8F2g==", "contentHash": "ajQ0aINQtEzWkqEXyJjnwqOFNusWNMHJVGrKa1ISbP21nrWJh+tApydLFVFGGjs91d7K3YOUbWDKlEzzdDQaOg==",
"dependencies": { "dependencies": {
"SkiaSharp": "2.80.2", "SkiaSharp": "2.80.2",
"SkiaSharp.HarfBuzz": "2.80.2", "SkiaSharp.HarfBuzz": "2.80.2",
"Svg.Custom": "0.5.7.2", "Svg.Custom": "0.5.8.3",
"Svg.Model": "0.5.7.2" "Svg.Model": "0.5.8.3"
} }
}, },
"System.AppContext": { "System.AppContext": {

View File

@ -1,6 +1,7 @@
using Artemis.Core.Ninject; using Artemis.Core.Ninject;
using Artemis.UI.Avalonia.Ninject; using Artemis.UI.Avalonia.Ninject;
using Artemis.UI.Avalonia.Screens.Root.ViewModels; using Artemis.UI.Avalonia.Screens.Root.ViewModels;
using Artemis.UI.Avalonia.Shared.Ninject;
using Avalonia; using Avalonia;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
@ -43,6 +44,7 @@ namespace Artemis.UI.Avalonia
_kernel = new StandardKernel(); _kernel = new StandardKernel();
_kernel.Load<CoreModule>(); _kernel.Load<CoreModule>();
_kernel.Load<UIModule>(); _kernel.Load<UIModule>();
_kernel.Load<SharedUIModule>();
_kernel.UseNinjectDependencyResolver(); _kernel.UseNinjectDependencyResolver();
} }

View File

@ -13,16 +13,17 @@
<None Remove="Assets\Images\home-banner.png" /> <None Remove="Assets\Images\home-banner.png" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.7" /> <PackageReference Include="Avalonia" Version="0.10.8" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.7" /> <PackageReference Include="Avalonia.Controls.PanAndZoom" Version="4.2.0" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.7" /> <PackageReference Include="Avalonia.Desktop" Version="0.10.8" />
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.7" /> <PackageReference Include="Avalonia.Diagnostics" Version="0.10.8" />
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.7.2" /> <PackageReference Include="Avalonia.ReactiveUI" Version="0.10.8" />
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.8.3" />
<PackageReference Include="FluentAvaloniaUI" Version="1.1.3" /> <PackageReference Include="FluentAvaloniaUI" Version="1.1.3" />
<PackageReference Include="Flurl.Http" Version="3.2.0" /> <PackageReference Include="Flurl.Http" Version="3.2.0" />
<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="Splat.Ninject" Version="13.1.22" /> <PackageReference Include="Splat.Ninject" Version="13.1.30" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" /> <ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" />

View File

@ -13,7 +13,7 @@
<ContentControl Grid.Column="0" Content="{Binding SidebarViewModel}" /> <ContentControl Grid.Column="0" Content="{Binding SidebarViewModel}" />
<Border Classes="router-container" Grid.Column="1"> <Border Classes="router-container" Grid.Column="1" Margin="0 40 0 0">
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" > <ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" >
<reactiveUi:RoutedViewHost Router="{Binding Router}"> <reactiveUi:RoutedViewHost Router="{Binding Router}">
<reactiveUi:RoutedViewHost.PageTransition> <reactiveUi:RoutedViewHost.PageTransition>

View File

@ -20,11 +20,13 @@ namespace Artemis.UI.Avalonia.Screens.Settings.ViewModels
{ {
private readonly PluginSetting<LayerBrushReference> _defaultLayerBrushDescriptor; private readonly PluginSetting<LayerBrushReference> _defaultLayerBrushDescriptor;
private readonly ISettingsService _settingsService; private readonly ISettingsService _settingsService;
private readonly IDebugService _debugService;
public GeneralTabViewModel(ISettingsService settingsService, IPluginManagementService pluginManagementService, IDebugService debuggerService) public GeneralTabViewModel(ISettingsService settingsService, IPluginManagementService pluginManagementService, IDebugService debugService)
{ {
DisplayName = "General"; DisplayName = "General";
_settingsService = settingsService; _settingsService = settingsService;
_debugService = debugService;
List<LayerBrushProvider> layerBrushProviders = pluginManagementService.GetFeaturesOfType<LayerBrushProvider>(); List<LayerBrushProvider> layerBrushProviders = pluginManagementService.GetFeaturesOfType<LayerBrushProvider>();
LayerBrushDescriptors = new ObservableCollection<LayerBrushDescriptor>(layerBrushProviders.SelectMany(l => l.LayerBrushDescriptors)); LayerBrushDescriptors = new ObservableCollection<LayerBrushDescriptor>(layerBrushProviders.SelectMany(l => l.LayerBrushDescriptors));
@ -137,8 +139,10 @@ namespace Artemis.UI.Avalonia.Screens.Settings.ViewModels
private void ExecuteShowDebugger() private void ExecuteShowDebugger()
{ {
_debugService.ShowDebugger();
} }
private void ExecuteShowDataFolder() private void ExecuteShowDataFolder()
{ {
OpenFolder(Constants.DataFolder); OpenFolder(Constants.DataFolder);

View File

@ -1,12 +1,18 @@
using ReactiveUI; using System.Collections.ObjectModel;
using Artemis.Core;
using Artemis.Core.Services;
using ReactiveUI;
namespace Artemis.UI.Avalonia.Screens.SurfaceEditor.ViewModels namespace Artemis.UI.Avalonia.Screens.SurfaceEditor.ViewModels
{ {
public class SurfaceEditorViewModel : MainScreenViewModel public class SurfaceEditorViewModel : MainScreenViewModel
{ {
public SurfaceEditorViewModel(IScreen hostScreen) : base(hostScreen, "surface-editor") public SurfaceEditorViewModel(IScreen hostScreen, IRgbService rgbService) : base(hostScreen, "surface-editor")
{ {
DisplayName = "Surface Editor"; DisplayName = "Surface Editor";
Devices = new ObservableCollection<ArtemisDevice>(rgbService.Devices);
} }
public ObservableCollection<ArtemisDevice> Devices { get; }
} }
} }

View File

@ -2,7 +2,50 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:Artemis.UI.Avalonia.Shared.Controls;assembly=Artemis.UI.Avalonia.Shared"
xmlns:paz="using:Avalonia.Controls.PanAndZoom"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Avalonia.Screens.SurfaceEditor.Views.SurfaceEditorView"> x:Class="Artemis.UI.Avalonia.Screens.SurfaceEditor.Views.SurfaceEditorView">
Surface editor c:
<paz:ZoomBorder Name="ZoomBorder"
Stretch="None"
ZoomSpeed="1.2"
ClipToBounds="True"
Focusable="True"
VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"
ZoomChanged="ZoomBorder_OnZoomChanged">
<paz:ZoomBorder.Background>
<VisualBrush TileMode="Tile" Stretch="Uniform" SourceRect="0,0,25,25">
<VisualBrush.Visual>
<Grid Width="25" Height="25" RowDefinitions="*,*" ColumnDefinitions="*,*">
<Rectangle Grid.Row="0" Grid.Column="0" Fill="Black" Opacity="0.15" />
<Rectangle Grid.Row="0" Grid.Column="1" />
<Rectangle Grid.Row="1" Grid.Column="0" />
<Rectangle Grid.Row="1" Grid.Column="1" Fill="Black" Opacity="0.15" />
</Grid>
</VisualBrush.Visual>
</VisualBrush>
</paz:ZoomBorder.Background>
<ItemsControl Items="{Binding Devices}">
<ItemsControl.Styles>
<Style Selector="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding X}" />
<Setter Property="Canvas.Top" Value="{Binding Y}" />
</Style>
</ItemsControl.Styles>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<controls:DeviceVisualizer
Device="{Binding}" ShowColors="True" />
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</paz:ZoomBorder>
</UserControl> </UserControl>

View File

@ -1,19 +1,33 @@
using Artemis.UI.Avalonia.Screens.SurfaceEditor.ViewModels; using Artemis.UI.Avalonia.Screens.SurfaceEditor.ViewModels;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.PanAndZoom;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Avalonia.ReactiveUI; using Avalonia.ReactiveUI;
namespace Artemis.UI.Avalonia.Screens.SurfaceEditor.Views namespace Artemis.UI.Avalonia.Screens.SurfaceEditor.Views
{ {
public class SurfaceEditorView : ReactiveUserControl<SurfaceEditorViewModel> public class SurfaceEditorView : ReactiveUserControl<SurfaceEditorViewModel>
{ {
private readonly ZoomBorder _zoomBorder;
public SurfaceEditorView() public SurfaceEditorView()
{ {
InitializeComponent(); InitializeComponent();
_zoomBorder = this.Find<ZoomBorder>("ZoomBorder");
((VisualBrush)_zoomBorder.Background).DestinationRect = new RelativeRect(_zoomBorder.OffsetX * -1, _zoomBorder.OffsetY * -1, 20, 20, RelativeUnit.Absolute);
} }
private void InitializeComponent() private void InitializeComponent()
{ {
AvaloniaXamlLoader.Load(this); AvaloniaXamlLoader.Load(this);
} }
private void ZoomBorder_OnZoomChanged(object sender, ZoomChangedEventArgs e)
{
((VisualBrush) _zoomBorder.Background).DestinationRect = new RelativeRect(_zoomBorder.OffsetX * -1, _zoomBorder.OffsetY * -1, 20, 20, RelativeUnit.Absolute);
}
} }
} }

View File

@ -1,30 +1,38 @@
using Artemis.UI.Avalonia.Screens.Debug; using Artemis.UI.Avalonia.Screens.Debug;
using Artemis.UI.Avalonia.Services.Interfaces; using Artemis.UI.Avalonia.Services.Interfaces;
using Ninject; using Artemis.UI.Avalonia.Shared.Services.Interfaces;
namespace Artemis.UI.Avalonia.Services namespace Artemis.UI.Avalonia.Services
{ {
public class DebugService : IDebugService public class DebugService : IDebugService
{ {
private readonly IKernel _kernel; private readonly IWindowService _windowService;
private DebugWindow? _debugWindow; private DebugViewModel? _debugViewModel;
public DebugService(IKernel kernel) public DebugService(IWindowService windowService)
{ {
_kernel = kernel; _windowService = windowService;
} }
private void CreateDebugger() public void ClearDebugger()
{ {
_debugViewModel = null;
} }
private void BringDebuggerToForeground() private void BringDebuggerToForeground()
{ {
if (_debugViewModel != null)
_debugViewModel.IsActive = true;
}
private void CreateDebugger()
{
_debugViewModel = _windowService.ShowWindow<DebugViewModel>();
} }
public void ShowDebugger() public void ShowDebugger()
{ {
if (_debugWindow != null) if (_debugViewModel != null)
BringDebuggerToForeground(); BringDebuggerToForeground();
else else
CreateDebugger(); CreateDebugger();

View File

@ -1,13 +1,8 @@
using System; namespace Artemis.UI.Avalonia.Services.Interfaces
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Artemis.UI.Avalonia.Services.Interfaces
{ {
public interface IDebugService : IArtemisUIService public interface IDebugService : IArtemisUIService
{ {
void ShowDebugger(); void ShowDebugger();
void ClearDebugger();
} }
} }

View File

@ -17,7 +17,6 @@
<!-- Add Styles Here --> <!-- Add Styles Here -->
<Style Selector="Border.router-container"> <Style Selector="Border.router-container">
<Setter Property="Margin" Value="0 40 0 0" />
<Setter Property="Background" Value="{DynamicResource SolidBackgroundFillColorTertiary}" /> <Setter Property="Background" Value="{DynamicResource SolidBackgroundFillColorTertiary}" />
<Setter Property="CornerRadius" Value="8 0 0 0" /> <Setter Property="CornerRadius" Value="8 0 0 0" />
<Setter Property="ClipToBounds" Value="True" /> <Setter Property="ClipToBounds" Value="True" />
@ -29,10 +28,10 @@
<Setter Property="CornerRadius" Value="10" /> <Setter Property="CornerRadius" Value="10" />
</Style> </Style>
<Style Selector="Separator.card-separator"> <Style Selector="Separator.card-separator">
<Setter Property="Background" Value="{DynamicResource ControlFillColorDefaultBrush}" /> <Setter Property="Background" Value="{DynamicResource ControlFillColorDefaultBrush}" />
<Setter Property="Margin" Value="-12 15" /> <Setter Property="Margin" Value="-12 15" />
<Setter Property="Height" Value="1" /> <Setter Property="Height" Value="1" />
</Style> </Style>
</Styles> </Styles>

View File

@ -4,11 +4,11 @@
".NETCoreApp,Version=v5.0": { ".NETCoreApp,Version=v5.0": {
"Avalonia": { "Avalonia": {
"type": "Direct", "type": "Direct",
"requested": "[0.10.7, )", "requested": "[0.10.8, )",
"resolved": "0.10.7", "resolved": "0.10.8",
"contentHash": "savkS5LlA3bGAXvP9RfPRLRjeGp7XXExNRNhM4BaxCHGsopsWOpRt0nNI6X7FrC9Ous3h+k+gKQu8kc+AZHj8A==", "contentHash": "/m31yPKz7iqV5thzlLGi8ERgiTV+FYl7NePafwDpN41aLwz8u4rrTviWm9QJH78cwj8tGCf9Pqp8Nm0fckfAZA==",
"dependencies": { "dependencies": {
"Avalonia.Remote.Protocol": "0.10.7", "Avalonia.Remote.Protocol": "0.10.8",
"JetBrains.Annotations": "10.3.0", "JetBrains.Annotations": "10.3.0",
"System.ComponentModel.Annotations": "4.5.0", "System.ComponentModel.Annotations": "4.5.0",
"System.Memory": "4.5.3", "System.Memory": "4.5.3",
@ -17,52 +17,61 @@
"System.ValueTuple": "4.5.0" "System.ValueTuple": "4.5.0"
} }
}, },
"Avalonia.Controls.PanAndZoom": {
"type": "Direct",
"requested": "[4.2.0, )",
"resolved": "4.2.0",
"contentHash": "zIQhp86CdV7xmFXFkaQBDNDr0WSyumEdJvqvIrywG5SEQK3HzACt0gR85KX19DHTlkJlnUVjmfkTEiPjwvgGtA==",
"dependencies": {
"Avalonia": "0.10.8"
}
},
"Avalonia.Desktop": { "Avalonia.Desktop": {
"type": "Direct", "type": "Direct",
"requested": "[0.10.7, )", "requested": "[0.10.8, )",
"resolved": "0.10.7", "resolved": "0.10.8",
"contentHash": "pSVPwUkGB37mzz1ZCW55y2ddiLYVw2bbHu1tmdwbJq1ZgL6xhyEIwCqFemwt2VR/dr74eN8CFlQuU8cHwFZFPA==", "contentHash": "DbY+6vMWR7i7mo5oVvPHhyui/LNsxfpXJaPNj3ka38EqcQOptZQI5DDrCHSAxGoFNrOsfNBTEs4Uv4rW5BW0Lg==",
"dependencies": { "dependencies": {
"Avalonia": "0.10.7", "Avalonia": "0.10.8",
"Avalonia.Native": "0.10.7", "Avalonia.Native": "0.10.8",
"Avalonia.Skia": "0.10.7", "Avalonia.Skia": "0.10.8",
"Avalonia.Win32": "0.10.7", "Avalonia.Win32": "0.10.8",
"Avalonia.X11": "0.10.7" "Avalonia.X11": "0.10.8"
} }
}, },
"Avalonia.Diagnostics": { "Avalonia.Diagnostics": {
"type": "Direct", "type": "Direct",
"requested": "[0.10.7, )", "requested": "[0.10.8, )",
"resolved": "0.10.7", "resolved": "0.10.8",
"contentHash": "SJHcdLfnIR0ImXxqDpQc5GzVcHWtRFJhPLU+kRDqt6z0JGdTbQviYBeVH/uywKVGzi/LgxCPOcC1gjSrV304Jw==", "contentHash": "nBvcRd5RFDpRli5z/gEbuUKHEhp6NCTUo3PWQFEYi9hOIVIgCqwgEljc9oo7FGPBA6HDbUZGqoopwFhbLXi+pg==",
"dependencies": { "dependencies": {
"Avalonia": "0.10.7", "Avalonia": "0.10.8",
"Avalonia.Controls.DataGrid": "0.10.7", "Avalonia.Controls.DataGrid": "0.10.8",
"Microsoft.CodeAnalysis.CSharp.Scripting": "3.4.0", "Microsoft.CodeAnalysis.CSharp.Scripting": "3.4.0",
"System.Reactive": "5.0.0" "System.Reactive": "5.0.0"
} }
}, },
"Avalonia.ReactiveUI": { "Avalonia.ReactiveUI": {
"type": "Direct", "type": "Direct",
"requested": "[0.10.7, )", "requested": "[0.10.8, )",
"resolved": "0.10.7", "resolved": "0.10.8",
"contentHash": "OjmGmTNforTPS9X2/+WqSbuu2h4hNl+N+6SKV83V3KeMKC4HNq6TqOTPNLF2yx2HOm/498I3kVGVXVL4Xan+cA==", "contentHash": "AnE4Rw9YQOLgHDK3TTkGXk3r4RCQgvYY/qMlspMfwdTyzJhvrjn7maDgAKhbs+m49Wr7dc9b1lfxqt7mNJWq/w==",
"dependencies": { "dependencies": {
"Avalonia": "0.10.7", "Avalonia": "0.10.8",
"ReactiveUI": "13.2.10", "ReactiveUI": "13.2.10",
"System.Reactive": "5.0.0" "System.Reactive": "5.0.0"
} }
}, },
"Avalonia.Svg.Skia": { "Avalonia.Svg.Skia": {
"type": "Direct", "type": "Direct",
"requested": "[0.10.7.2, )", "requested": "[0.10.8.3, )",
"resolved": "0.10.7.2", "resolved": "0.10.8.3",
"contentHash": "a5zt8IwrLeG+2hQ+Hs7/2zjPH5vujFQvcmOOWikM9iktm6Vjejqj8h1ssZK3n4TfGmIkq2AtbQcTBAC1nqFP6A==", "contentHash": "w7RYf+8+gOI3uVZZJ59S0EP49LVsyr1jpnZQzVFQqKa3y/c/i2jT/EUoKOeaqPMhFIsQZyEF4iluqoo6aZ05Tw==",
"dependencies": { "dependencies": {
"Avalonia": "0.10.7", "Avalonia": "0.10.8",
"Avalonia.Skia": "0.10.7", "Avalonia.Skia": "0.10.8",
"SkiaSharp": "2.80.2", "SkiaSharp": "2.80.2",
"Svg.Skia": "0.5.7.2" "Svg.Skia": "0.5.8.3"
} }
}, },
"FluentAvaloniaUI": { "FluentAvaloniaUI": {
@ -108,12 +117,12 @@
}, },
"Splat.Ninject": { "Splat.Ninject": {
"type": "Direct", "type": "Direct",
"requested": "[13.1.22, )", "requested": "[13.1.30, )",
"resolved": "13.1.22", "resolved": "13.1.30",
"contentHash": "wRqjUyT6L7G5v7oT75TzQs7knrtZgYF7pNyHoaeJ9sm0aLlzWwy9Z6faZWZ/3fXXJf3IokRFCSXmQSq18UyW4Q==", "contentHash": "hYgyD12Syt2l8U/KccMzNUj4nmrdULjoRTF4g5Q9XtVWPrcdTYmLEdcX/prZEWaFT7vGNP6x9uFXvOlM7Jc+gg==",
"dependencies": { "dependencies": {
"Ninject": "3.3.4", "Ninject": "3.3.4",
"Splat": "13.1.22" "Splat": "13.1.30"
} }
}, },
"Avalonia.Angle.Windows.Natives": { "Avalonia.Angle.Windows.Natives": {
@ -123,43 +132,43 @@
}, },
"Avalonia.Controls.DataGrid": { "Avalonia.Controls.DataGrid": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.10.7", "resolved": "0.10.8",
"contentHash": "AEQ/4We8qak7A3CAWboPvub7AyFH8SdXyoFGVWiJCHRQPy30/apNL5O/dccYnQ2ANO+yTwZxU0mL8RoAJgp+0Q==", "contentHash": "AWS/s+tEDUX0icnDdsMpk6NoLAZeq+QEIiDhleJkxMTitfwvYVJlXePaoOm4w8Oi134KV/fkj7aoiU3QRr/ltg==",
"dependencies": { "dependencies": {
"Avalonia": "0.10.7", "Avalonia": "0.10.8",
"Avalonia.Remote.Protocol": "0.10.7", "Avalonia.Remote.Protocol": "0.10.8",
"JetBrains.Annotations": "10.3.0", "JetBrains.Annotations": "10.3.0",
"System.Reactive": "5.0.0" "System.Reactive": "5.0.0"
} }
}, },
"Avalonia.FreeDesktop": { "Avalonia.FreeDesktop": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.10.7", "resolved": "0.10.8",
"contentHash": "zMjjAqujGe9TiBdst8iHTIAoR0cprR6bxiGrz2Pw/HqbghoM08vv5fHsqCtJVwexdSopkOkge5jkYsKlbl5pdQ==", "contentHash": "QvkzItAsww8zZmKyEKXMmhIN+ZnV8h3FGikNhqWjvVHSDQkaZ2FfltQ+MH7011lO7z+igkNshXRBfs+HB2syXw==",
"dependencies": { "dependencies": {
"Avalonia": "0.10.7", "Avalonia": "0.10.8",
"Tmds.DBus": "0.9.0" "Tmds.DBus": "0.9.0"
} }
}, },
"Avalonia.Native": { "Avalonia.Native": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.10.7", "resolved": "0.10.8",
"contentHash": "1rrTEtvMhIU4atfd6l1nI8npazX2E65cwZ3J66/7lxXaGc/xgYKbZ/uKFHODfv9TRdxRmvcwxk6azJV/Ej86Vg==", "contentHash": "FfIeLXDycQglDFqC6KnqgjPFCMZIemgPiB2ShZ8xzqwwFJFKd9WpOSDsEImASSqTVMra0se55vP/Ey2TO7ZVvA==",
"dependencies": { "dependencies": {
"Avalonia": "0.10.7" "Avalonia": "0.10.8"
} }
}, },
"Avalonia.Remote.Protocol": { "Avalonia.Remote.Protocol": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.10.7", "resolved": "0.10.8",
"contentHash": "w8Le0g2StgD1/32mEPYzP0MhMfDyeHvATHFV3IYA2oQTiPoicjUy3To+PuwAB9T9SSi9DtkLhwazlWZOqQGuAw==" "contentHash": "flpM/ZF2vkzbHbmSKdq6qWxy/bw/2C1k3Oc73ewlUdwBUWMov6mX99yUWNNI26oYrgD2fpaRhHMukcoSCYqbuQ=="
}, },
"Avalonia.Skia": { "Avalonia.Skia": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.10.7", "resolved": "0.10.8",
"contentHash": "dV6WXLk5ziYhnDAwf/fagoVRPTBN4LvFt1BMgikvVKCrkWlmtnQQ/Rav9ESJ13c887XpWMGcERYne3vzeLP6MA==", "contentHash": "FsCeOhzDCE4GJnqBGzH/54tqsn0j39Xpkdf3TmuC0MZzjW82Me3GUGeO25E9zs7sEMtX0MKWocmBx6c6ADcGXA==",
"dependencies": { "dependencies": {
"Avalonia": "0.10.7", "Avalonia": "0.10.8",
"HarfBuzzSharp": "2.6.1.7", "HarfBuzzSharp": "2.6.1.7",
"HarfBuzzSharp.NativeAssets.Linux": "2.6.1.7", "HarfBuzzSharp.NativeAssets.Linux": "2.6.1.7",
"SkiaSharp": "2.80.2", "SkiaSharp": "2.80.2",
@ -168,10 +177,10 @@
}, },
"Avalonia.Win32": { "Avalonia.Win32": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.10.7", "resolved": "0.10.8",
"contentHash": "pJvd+kYHyZ8OOvThrZ0BkRfTS9xky92pYJ4Aeu8qukdSpTPV06pp5razXNr6FrkVx3CK/3oB8XzLOJdxpRA/VQ==", "contentHash": "OUuzYGw4h+9KMvJZkX0bZbQ4T5TTkGdJSyfUdq/WTc4PFV0mp7fF+ofBMSVfFFDsw+7WmGJgN8ZqoPLGFFaPRw==",
"dependencies": { "dependencies": {
"Avalonia": "0.10.7", "Avalonia": "0.10.8",
"Avalonia.Angle.Windows.Natives": "2.1.0.2020091801", "Avalonia.Angle.Windows.Natives": "2.1.0.2020091801",
"System.Drawing.Common": "4.5.0", "System.Drawing.Common": "4.5.0",
"System.Numerics.Vectors": "4.5.0" "System.Numerics.Vectors": "4.5.0"
@ -179,39 +188,39 @@
}, },
"Avalonia.X11": { "Avalonia.X11": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.10.7", "resolved": "0.10.8",
"contentHash": "rvmP/TiEUlCtWio4lJGquW/8+1AI+4MNCWNF4ygPlSj1Z9T38FjFXVPM8Cok2W6U8Y4HTrLo4frN4HTiJAtfdw==", "contentHash": "kjzH9q4ZfLIdSoVe9e5lABmpEGs85B7RSk3aynnMDHldwya8mDNOPD6urItNrxQgiU1vOzPXGNjt1WBtveyOkw==",
"dependencies": { "dependencies": {
"Avalonia": "0.10.7", "Avalonia": "0.10.8",
"Avalonia.FreeDesktop": "0.10.7", "Avalonia.FreeDesktop": "0.10.8",
"Avalonia.Skia": "0.10.7" "Avalonia.Skia": "0.10.8"
} }
}, },
"Avalonia.Xaml.Behaviors": { "Avalonia.Xaml.Behaviors": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.10.7.1", "resolved": "0.10.8",
"contentHash": "Ef5PCejEA6F25GadMwVVqATeWrZ7XFouerQvbeIpH2FOD8iS8Vg8vEJFGkHLv1N6HHUF2nZUb01csfs6bOy4Jg==", "contentHash": "3nkh36Qp9fK8/Fh/nxqaVMlAzj8iuH5RUcs2rTrcyqn1WPJTslwQrxk+HDMYneuBE9+Oi31ZWiZImEM9kEQN7w==",
"dependencies": { "dependencies": {
"Avalonia": "0.10.7", "Avalonia": "0.10.8",
"Avalonia.Xaml.Interactions": "0.10.7.1", "Avalonia.Xaml.Interactions": "0.10.8",
"Avalonia.Xaml.Interactivity": "0.10.7.1" "Avalonia.Xaml.Interactivity": "0.10.8"
} }
}, },
"Avalonia.Xaml.Interactions": { "Avalonia.Xaml.Interactions": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.10.7.1", "resolved": "0.10.8",
"contentHash": "ZFgGnjUKbZofMAriGn8xPW/3rt1iww2pUTtOQW8+8YQDtFBjZtq2LaiE0ExX9HgPqgrFM8LYwGcf8SsYZb1pNg==", "contentHash": "3pXshQ1pNr+ul7Q2Sn6jjWMHOgRM2uKsUCh95QD2O2wpjgxpRpqiNEy1xPv2+bX2FMWTQIaOdQ8eNM8EunAWMg==",
"dependencies": { "dependencies": {
"Avalonia": "0.10.7", "Avalonia": "0.10.8",
"Avalonia.Xaml.Interactivity": "0.10.7.1" "Avalonia.Xaml.Interactivity": "0.10.8"
} }
}, },
"Avalonia.Xaml.Interactivity": { "Avalonia.Xaml.Interactivity": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.10.7.1", "resolved": "0.10.8",
"contentHash": "vLYy2lRISft55wwU7gKTXdBfbdkas1u/bznO05IYCFQzwVRo5ktSs1U1fy6ZzrK5z9Lq/e05GM7Q123n4Dfpow==", "contentHash": "ObL26GjME53R3KRkGB97dIB3jwGzyNS/7Www8fZjCEbK4AnjXVgzyw7gkHNsHD9DEZArovvURQI0qvvz3tb24g==",
"dependencies": { "dependencies": {
"Avalonia": "0.10.7" "Avalonia": "0.10.8"
} }
}, },
"Castle.Core": { "Castle.Core": {
@ -659,8 +668,8 @@
}, },
"ShimSkiaSharp": { "ShimSkiaSharp": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.5.7.2", "resolved": "0.5.8.3",
"contentHash": "+KFniLMpqei3Hj1T586ZY/ZDZXXyl6NFLTXvSZ5LvEi96KIcEgbFCuSsNCVfTmnKQaLCn4Gn+KHjqroCJe2FFA==" "contentHash": "BWwwsIlYUFF0DUc8Pa9xONIXVDvEL9pOYc9YmWilpHrWC37dcK+H4+tfuxztZxtfJx559HGn+6iZmMDjfFoOxA=="
}, },
"SkiaSharp": { "SkiaSharp": {
"type": "Transitive", "type": "Transitive",
@ -689,13 +698,13 @@
}, },
"Splat": { "Splat": {
"type": "Transitive", "type": "Transitive",
"resolved": "13.1.22", "resolved": "13.1.30",
"contentHash": "0t7eWbu2Ub80kdZjkvXa6r/ZLDAPM/q6WDALkpK4urdGUHl5q2XAmuo5QM0CcIWaEt8AFff8mx0H7qE9PxkG7A==" "contentHash": "yaj3r8CvHQwtvhfTi+dp5LpIb3c4svqe/tL6LdAS8wWP+dXAp3fTCLjYx21TrW1QBFTBJcg9lrJqDPbheSzHbA=="
}, },
"Svg.Custom": { "Svg.Custom": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.5.7.2", "resolved": "0.5.8.3",
"contentHash": "BLb8ViaXEWWsYvbxtGj+ITNO1CpZEszWT8sE5Xa1qkeoniIENog5PEKGTc5mAJ8MhFc4GYO33Vo9duH0KzizNQ==", "contentHash": "6FnbI4T3uCNN7DYJpfPFa4caTTJzp4YbhU3J4c/syX7wQNSeQ/1u7JZZ+dGgrRUauiWP8VsiCLKP8qinc5xI5w==",
"dependencies": { "dependencies": {
"Fizzler": "1.2.0", "Fizzler": "1.2.0",
"System.Drawing.Common": "5.0.0", "System.Drawing.Common": "5.0.0",
@ -706,22 +715,22 @@
}, },
"Svg.Model": { "Svg.Model": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.5.7.2", "resolved": "0.5.8.3",
"contentHash": "txH95pxkg75s2LBcONXFCmrpYp5flUC5aF1DaLwTtt33dv9WvOQQlxnasNyb0CN7t0yaXpX8CZoo+SU9u1E/eA==", "contentHash": "F/rimPwV5KF64P8oofXGMwOZ0T7b3z1A9OiC4mv5OdSpLpMpUxpSwGLAOkJ5DFqQgXqVjKKLhPdjIjQBwy0AjA==",
"dependencies": { "dependencies": {
"ShimSkiaSharp": "0.5.7.2", "ShimSkiaSharp": "0.5.8.3",
"Svg.Custom": "0.5.7.2" "Svg.Custom": "0.5.8.3"
} }
}, },
"Svg.Skia": { "Svg.Skia": {
"type": "Transitive", "type": "Transitive",
"resolved": "0.5.7.2", "resolved": "0.5.8.3",
"contentHash": "QknpGmwSsns+/05W4efAuPvd77AsimuN5bAGTHGzHQPkPY/htgfXPm2YKywsEIpbXvUiTCfvzaSxSlkYHK8F2g==", "contentHash": "ajQ0aINQtEzWkqEXyJjnwqOFNusWNMHJVGrKa1ISbP21nrWJh+tApydLFVFGGjs91d7K3YOUbWDKlEzzdDQaOg==",
"dependencies": { "dependencies": {
"SkiaSharp": "2.80.2", "SkiaSharp": "2.80.2",
"SkiaSharp.HarfBuzz": "2.80.2", "SkiaSharp.HarfBuzz": "2.80.2",
"Svg.Custom": "0.5.7.2", "Svg.Custom": "0.5.8.3",
"Svg.Model": "0.5.7.2" "Svg.Model": "0.5.8.3"
} }
}, },
"System.AppContext": { "System.AppContext": {
@ -1685,11 +1694,11 @@
"type": "Project", "type": "Project",
"dependencies": { "dependencies": {
"Artemis.Core": "1.0.0", "Artemis.Core": "1.0.0",
"Avalonia": "0.10.7", "Avalonia": "0.10.8",
"Avalonia.Svg.Skia": "0.10.7.2", "Avalonia.Svg.Skia": "0.10.8.3",
"Avalonia.Xaml.Behaviors": "0.10.7.1", "Avalonia.Xaml.Behaviors": "0.10.8",
"Avalonia.Xaml.Interactions": "0.10.7.1", "Avalonia.Xaml.Interactions": "0.10.8",
"Avalonia.Xaml.Interactivity": "0.10.7.1", "Avalonia.Xaml.Interactivity": "0.10.8",
"Material.Icons.Avalonia": "1.0.2" "Material.Icons.Avalonia": "1.0.2"
} }
} }