1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +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
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))));
}

View File

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

View File

@ -12,7 +12,10 @@ using Avalonia.Input;
using Avalonia.LogicalTree;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using Avalonia.Rendering;
using Avalonia.Threading;
using Avalonia.Visuals.Media.Imaging;
namespace Artemis.UI.Avalonia.Shared.Controls
{
@ -21,10 +24,11 @@ namespace Artemis.UI.Avalonia.Shared.Controls
/// </summary>
public class DeviceVisualizer : Control
{
private readonly DispatcherTimer _timer;
private const double UpdateFrameRate = 25.0;
private readonly List<DeviceVisualizerLed> _deviceVisualizerLeds;
private readonly DispatcherTimer _timer;
private Bitmap? _deviceImage;
private RenderTargetBitmap? _deviceImage;
private List<DeviceVisualizerLed>? _dimmedLeds;
private List<DeviceVisualizerLed>? _highlightedLeds;
private ArtemisDevice? _oldDevice;
@ -32,8 +36,7 @@ namespace Artemis.UI.Avalonia.Shared.Controls
/// <inheritdoc />
public DeviceVisualizer()
{
// Run an update timer at 25 fps
_timer = new DispatcherTimer(DispatcherPriority.Render) {Interval = TimeSpan.FromMilliseconds(40)};
_timer = new DispatcherTimer(DispatcherPriority.Render) {Interval = TimeSpan.FromMilliseconds(1000.0 / UpdateFrameRate)};
_deviceVisualizerLeds = new List<DeviceVisualizerLed>();
PointerReleased += OnPointerReleased;
@ -45,27 +48,35 @@ namespace Artemis.UI.Avalonia.Shared.Controls
if (Device == null)
return;
List<DrawingContext.PushedState> pushes = new(4);
// Determine the scale required to fit the desired size of the control
Rect measureSize = MeasureDevice();
double scale = Math.Min(Bounds.Width / measureSize.Width, Bounds.Height / measureSize.Height);
// Scale the visualization in the desired bounding box
if (Bounds.Width > 0 && Bounds.Height > 0)
drawingContext.PushPostTransform(Matrix.CreateScale(scale, scale));
pushes.Add(drawingContext.PushPostTransform(Matrix.CreateScale(scale, scale)));
// Apply device rotation
drawingContext.PushPostTransform(Matrix.CreateTranslation(0 - measureSize.Left, 0 - measureSize.Top));
drawingContext.PushPostTransform(Matrix.CreateRotation(Device.Rotation));
pushes.Add(drawingContext.PushPostTransform(Matrix.CreateTranslation(0 - measureSize.Left, 0 - measureSize.Top)));
pushes.Add(drawingContext.PushPostTransform(Matrix.CreateRotation(Device.Rotation)));
// 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
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)
deviceVisualizerLed.RenderImage(drawingContext);
deviceVisualizerLed.RenderGeometry(drawingContext);
for (int index = pushes.Count - 1; index >= 0; index--)
{
DrawingContext.PushedState pushedState = pushes[index];
pushedState.Dispose();
}
}
/// <summary>
@ -73,6 +84,13 @@ namespace Artemis.UI.Avalonia.Shared.Controls
/// </summary>
public event EventHandler<LedClickedEventArgs>? LedClicked;
protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e)
{
_deviceImage?.Dispose();
_deviceImage = null;
base.OnDetachedFromVisualTree(e);
}
/// <summary>
/// Invokes the <see cref="LedClicked" /> event
/// </summary>
@ -142,7 +160,13 @@ namespace Artemis.UI.Avalonia.Shared.Controls
/// Gets or sets the <see cref="ArtemisDevice" /> to display
/// </summary>
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>
/// Gets or sets the <see cref="ArtemisDevice" /> to display
@ -225,14 +249,32 @@ namespace Artemis.UI.Avalonia.Shared.Controls
Device.DeviceUpdated += DeviceUpdated;
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
foreach (ArtemisLed artemisLed in Device.Leds)
_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();
}

View File

@ -4,6 +4,8 @@ using Artemis.Core;
using Avalonia;
using Avalonia.Media;
using Avalonia.Media.Imaging;
using Avalonia.Platform;
using Avalonia.Visuals.Media.Imaging;
using RGB.NET.Core;
using Color = Avalonia.Media.Color;
using Point = Avalonia.Point;
@ -13,6 +15,9 @@ namespace Artemis.UI.Avalonia.Shared.Controls
{
internal class DeviceVisualizerLed
{
private readonly SolidColorBrush _penBrush;
private readonly SolidColorBrush _fillBrush;
private readonly Pen _pen;
private const byte Dimmed = 100;
private const byte NonDimmed = 255;
@ -26,46 +31,54 @@ namespace Artemis.UI.Avalonia.Shared.Controls
Led.RgbLed.Size.Height
);
if (Led.Layout?.Image != null && File.Exists(Led.Layout.Image.LocalPath))
LedImage = new Bitmap(Led.Layout.Image.AbsolutePath);
_fillBrush = new SolidColorBrush();
_penBrush = new SolidColorBrush();
_pen = new Pen(_penBrush) {LineJoin = PenLineJoin.Round};
CreateLedGeometry();
}
public ArtemisLed Led { get; }
public Rect LedRect { get; set; }
public Bitmap? LedImage { get; 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;
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 g = Led.RgbLed.Color.GetG();
byte b = Led.RgbLed.Color.GetB();
SolidColorBrush fillBrush = new(new Color(100, r, g, b));
SolidColorBrush penBrush = new(new Color(255, r, g, b));
_fillBrush.Color = new Color(100, 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
drawingContext.DrawGeometry(fillBrush, new Pen(penBrush) {LineJoin = PenLineJoin.Round}, DisplayGeometry);
drawingContext.DrawGeometry(_fillBrush, _pen, DisplayGeometry);
}
public bool HitTest(Point position)
{
if (DisplayGeometry == null)
return false;
Geometry translatedGeometry = DisplayGeometry.Clone();
translatedGeometry.Transform = new TranslateTransform(Led.RgbLed.Location.X, Led.RgbLed.Location.Y);
return translatedGeometry.FillContains(position);
return DisplayGeometry != null && DisplayGeometry.FillContains(position);
}
private void CreateLedGeometry()
@ -98,26 +111,17 @@ namespace Artemis.UI.Avalonia.Shared.Controls
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()
{
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()
{
PathGeometry path = PathGeometry.Parse($"M1,1" +
$"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;
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));
}
private void CreateCustomGeometry(double deflateAmount)
@ -128,27 +132,15 @@ namespace Artemis.UI.Avalonia.Shared.Controls
double height = Led.RgbLed.Size.Height - deflateAmount;
Geometry geometry = Geometry.Parse(Led.RgbLed.ShapeData);
geometry.Transform = new ScaleTransform(width, height);
geometry = geometry.Clone();
geometry.Transform = new TranslateTransform(deflateAmount / 2, deflateAmount / 2);
DisplayGeometry = geometry.Clone();
// TODO: Figure out wtf was going on here
// if (DisplayGeometry.Bounds.Width > width)
// {
// DisplayGeometry = Geometry.Combine(Geometry.Empty, DisplayGeometry, GeometryCombineMode.Union, new TransformGroup
// {
// 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)}
// });
// }
geometry.Transform = new TransformGroup
{
Children = new Transforms
{
new ScaleTransform(width, height),
new TranslateTransform(Led.RgbLed.Location.X + deflateAmount / 2, Led.RgbLed.Location.Y + deflateAmount / 2)
}
};
DisplayGeometry = geometry;
}
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": {
"Avalonia": {
"type": "Direct",
"requested": "[0.10.7, )",
"resolved": "0.10.7",
"contentHash": "savkS5LlA3bGAXvP9RfPRLRjeGp7XXExNRNhM4BaxCHGsopsWOpRt0nNI6X7FrC9Ous3h+k+gKQu8kc+AZHj8A==",
"requested": "[0.10.8, )",
"resolved": "0.10.8",
"contentHash": "/m31yPKz7iqV5thzlLGi8ERgiTV+FYl7NePafwDpN41aLwz8u4rrTviWm9QJH78cwj8tGCf9Pqp8Nm0fckfAZA==",
"dependencies": {
"Avalonia.Remote.Protocol": "0.10.7",
"Avalonia.Remote.Protocol": "0.10.8",
"JetBrains.Annotations": "10.3.0",
"System.ComponentModel.Annotations": "4.5.0",
"System.Memory": "4.5.3",
@ -19,44 +19,44 @@
},
"Avalonia.Svg.Skia": {
"type": "Direct",
"requested": "[0.10.7.2, )",
"resolved": "0.10.7.2",
"contentHash": "a5zt8IwrLeG+2hQ+Hs7/2zjPH5vujFQvcmOOWikM9iktm6Vjejqj8h1ssZK3n4TfGmIkq2AtbQcTBAC1nqFP6A==",
"requested": "[0.10.8.3, )",
"resolved": "0.10.8.3",
"contentHash": "w7RYf+8+gOI3uVZZJ59S0EP49LVsyr1jpnZQzVFQqKa3y/c/i2jT/EUoKOeaqPMhFIsQZyEF4iluqoo6aZ05Tw==",
"dependencies": {
"Avalonia": "0.10.7",
"Avalonia.Skia": "0.10.7",
"Avalonia": "0.10.8",
"Avalonia.Skia": "0.10.8",
"SkiaSharp": "2.80.2",
"Svg.Skia": "0.5.7.2"
"Svg.Skia": "0.5.8.3"
}
},
"Avalonia.Xaml.Behaviors": {
"type": "Direct",
"requested": "[0.10.7.1, )",
"resolved": "0.10.7.1",
"contentHash": "Ef5PCejEA6F25GadMwVVqATeWrZ7XFouerQvbeIpH2FOD8iS8Vg8vEJFGkHLv1N6HHUF2nZUb01csfs6bOy4Jg==",
"requested": "[0.10.8, )",
"resolved": "0.10.8",
"contentHash": "3nkh36Qp9fK8/Fh/nxqaVMlAzj8iuH5RUcs2rTrcyqn1WPJTslwQrxk+HDMYneuBE9+Oi31ZWiZImEM9kEQN7w==",
"dependencies": {
"Avalonia": "0.10.7",
"Avalonia.Xaml.Interactions": "0.10.7.1",
"Avalonia.Xaml.Interactivity": "0.10.7.1"
"Avalonia": "0.10.8",
"Avalonia.Xaml.Interactions": "0.10.8",
"Avalonia.Xaml.Interactivity": "0.10.8"
}
},
"Avalonia.Xaml.Interactions": {
"type": "Direct",
"requested": "[0.10.7.1, )",
"resolved": "0.10.7.1",
"contentHash": "ZFgGnjUKbZofMAriGn8xPW/3rt1iww2pUTtOQW8+8YQDtFBjZtq2LaiE0ExX9HgPqgrFM8LYwGcf8SsYZb1pNg==",
"requested": "[0.10.8, )",
"resolved": "0.10.8",
"contentHash": "3pXshQ1pNr+ul7Q2Sn6jjWMHOgRM2uKsUCh95QD2O2wpjgxpRpqiNEy1xPv2+bX2FMWTQIaOdQ8eNM8EunAWMg==",
"dependencies": {
"Avalonia": "0.10.7",
"Avalonia.Xaml.Interactivity": "0.10.7.1"
"Avalonia": "0.10.8",
"Avalonia.Xaml.Interactivity": "0.10.8"
}
},
"Avalonia.Xaml.Interactivity": {
"type": "Direct",
"requested": "[0.10.7.1, )",
"resolved": "0.10.7.1",
"contentHash": "vLYy2lRISft55wwU7gKTXdBfbdkas1u/bznO05IYCFQzwVRo5ktSs1U1fy6ZzrK5z9Lq/e05GM7Q123n4Dfpow==",
"requested": "[0.10.8, )",
"resolved": "0.10.8",
"contentHash": "ObL26GjME53R3KRkGB97dIB3jwGzyNS/7Www8fZjCEbK4AnjXVgzyw7gkHNsHD9DEZArovvURQI0qvvz3tb24g==",
"dependencies": {
"Avalonia": "0.10.7"
"Avalonia": "0.10.8"
}
},
"Material.Icons.Avalonia": {
@ -71,15 +71,15 @@
},
"Avalonia.Remote.Protocol": {
"type": "Transitive",
"resolved": "0.10.7",
"contentHash": "w8Le0g2StgD1/32mEPYzP0MhMfDyeHvATHFV3IYA2oQTiPoicjUy3To+PuwAB9T9SSi9DtkLhwazlWZOqQGuAw=="
"resolved": "0.10.8",
"contentHash": "flpM/ZF2vkzbHbmSKdq6qWxy/bw/2C1k3Oc73ewlUdwBUWMov6mX99yUWNNI26oYrgD2fpaRhHMukcoSCYqbuQ=="
},
"Avalonia.Skia": {
"type": "Transitive",
"resolved": "0.10.7",
"contentHash": "dV6WXLk5ziYhnDAwf/fagoVRPTBN4LvFt1BMgikvVKCrkWlmtnQQ/Rav9ESJ13c887XpWMGcERYne3vzeLP6MA==",
"resolved": "0.10.8",
"contentHash": "FsCeOhzDCE4GJnqBGzH/54tqsn0j39Xpkdf3TmuC0MZzjW82Me3GUGeO25E9zs7sEMtX0MKWocmBx6c6ADcGXA==",
"dependencies": {
"Avalonia": "0.10.7",
"Avalonia": "0.10.8",
"HarfBuzzSharp": "2.6.1.7",
"HarfBuzzSharp.NativeAssets.Linux": "2.6.1.7",
"SkiaSharp": "2.80.2",
@ -438,8 +438,8 @@
},
"ShimSkiaSharp": {
"type": "Transitive",
"resolved": "0.5.7.2",
"contentHash": "+KFniLMpqei3Hj1T586ZY/ZDZXXyl6NFLTXvSZ5LvEi96KIcEgbFCuSsNCVfTmnKQaLCn4Gn+KHjqroCJe2FFA=="
"resolved": "0.5.8.3",
"contentHash": "BWwwsIlYUFF0DUc8Pa9xONIXVDvEL9pOYc9YmWilpHrWC37dcK+H4+tfuxztZxtfJx559HGn+6iZmMDjfFoOxA=="
},
"SkiaSharp": {
"type": "Transitive",
@ -468,8 +468,8 @@
},
"Svg.Custom": {
"type": "Transitive",
"resolved": "0.5.7.2",
"contentHash": "BLb8ViaXEWWsYvbxtGj+ITNO1CpZEszWT8sE5Xa1qkeoniIENog5PEKGTc5mAJ8MhFc4GYO33Vo9duH0KzizNQ==",
"resolved": "0.5.8.3",
"contentHash": "6FnbI4T3uCNN7DYJpfPFa4caTTJzp4YbhU3J4c/syX7wQNSeQ/1u7JZZ+dGgrRUauiWP8VsiCLKP8qinc5xI5w==",
"dependencies": {
"Fizzler": "1.2.0",
"System.Drawing.Common": "5.0.0",
@ -480,22 +480,22 @@
},
"Svg.Model": {
"type": "Transitive",
"resolved": "0.5.7.2",
"contentHash": "txH95pxkg75s2LBcONXFCmrpYp5flUC5aF1DaLwTtt33dv9WvOQQlxnasNyb0CN7t0yaXpX8CZoo+SU9u1E/eA==",
"resolved": "0.5.8.3",
"contentHash": "F/rimPwV5KF64P8oofXGMwOZ0T7b3z1A9OiC4mv5OdSpLpMpUxpSwGLAOkJ5DFqQgXqVjKKLhPdjIjQBwy0AjA==",
"dependencies": {
"ShimSkiaSharp": "0.5.7.2",
"Svg.Custom": "0.5.7.2"
"ShimSkiaSharp": "0.5.8.3",
"Svg.Custom": "0.5.8.3"
}
},
"Svg.Skia": {
"type": "Transitive",
"resolved": "0.5.7.2",
"contentHash": "QknpGmwSsns+/05W4efAuPvd77AsimuN5bAGTHGzHQPkPY/htgfXPm2YKywsEIpbXvUiTCfvzaSxSlkYHK8F2g==",
"resolved": "0.5.8.3",
"contentHash": "ajQ0aINQtEzWkqEXyJjnwqOFNusWNMHJVGrKa1ISbP21nrWJh+tApydLFVFGGjs91d7K3YOUbWDKlEzzdDQaOg==",
"dependencies": {
"SkiaSharp": "2.80.2",
"SkiaSharp.HarfBuzz": "2.80.2",
"Svg.Custom": "0.5.7.2",
"Svg.Model": "0.5.7.2"
"Svg.Custom": "0.5.8.3",
"Svg.Model": "0.5.8.3"
}
},
"System.AppContext": {

View File

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

View File

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

View File

@ -13,7 +13,7 @@
<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" >
<reactiveUi:RoutedViewHost Router="{Binding Router}">
<reactiveUi:RoutedViewHost.PageTransition>

View File

@ -20,11 +20,13 @@ namespace Artemis.UI.Avalonia.Screens.Settings.ViewModels
{
private readonly PluginSetting<LayerBrushReference> _defaultLayerBrushDescriptor;
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";
_settingsService = settingsService;
_debugService = debugService;
List<LayerBrushProvider> layerBrushProviders = pluginManagementService.GetFeaturesOfType<LayerBrushProvider>();
LayerBrushDescriptors = new ObservableCollection<LayerBrushDescriptor>(layerBrushProviders.SelectMany(l => l.LayerBrushDescriptors));
@ -137,8 +139,10 @@ namespace Artemis.UI.Avalonia.Screens.Settings.ViewModels
private void ExecuteShowDebugger()
{
_debugService.ShowDebugger();
}
private void ExecuteShowDataFolder()
{
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
{
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";
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:d="http://schemas.microsoft.com/expression/blend/2008"
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"
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>

View File

@ -1,19 +1,33 @@
using Artemis.UI.Avalonia.Screens.SurfaceEditor.ViewModels;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Controls.PanAndZoom;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Avalonia.Screens.SurfaceEditor.Views
{
public class SurfaceEditorView : ReactiveUserControl<SurfaceEditorViewModel>
{
private readonly ZoomBorder _zoomBorder;
public SurfaceEditorView()
{
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()
{
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.Services.Interfaces;
using Ninject;
using Artemis.UI.Avalonia.Shared.Services.Interfaces;
namespace Artemis.UI.Avalonia.Services
{
public class DebugService : IDebugService
{
private readonly IKernel _kernel;
private DebugWindow? _debugWindow;
private readonly IWindowService _windowService;
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()
{
if (_debugViewModel != null)
_debugViewModel.IsActive = true;
}
private void CreateDebugger()
{
_debugViewModel = _windowService.ShowWindow<DebugViewModel>();
}
public void ShowDebugger()
{
if (_debugWindow != null)
if (_debugViewModel != null)
BringDebuggerToForeground();
else
CreateDebugger();

View File

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

View File

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

View File

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