mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Merge branch 'development'
This commit is contained in:
commit
ff6efe9456
@ -1,6 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<Import Project="..\Artemis.props" />
|
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<PreserveCompilationContext>false</PreserveCompilationContext>
|
<PreserveCompilationContext>false</PreserveCompilationContext>
|
||||||
@ -38,27 +36,20 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="DryIoc.dll" Version="5.4.1" />
|
<PackageReference Include="DryIoc.dll" Version="5.4.3" />
|
||||||
<PackageReference Include="EmbedIO" Version="3.5.2" />
|
<PackageReference Include="EmbedIO" Version="3.5.2" />
|
||||||
<PackageReference Include="HidSharp" Version="2.1.0" />
|
<PackageReference Include="HidSharp" Version="2.1.0" />
|
||||||
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
<PackageReference Include="Humanizer.Core" Version="2.14.1" />
|
||||||
<PackageReference Include="JetBrains.Annotations" Version="2023.2.0" />
|
<PackageReference Include="JetBrains.Annotations" Version="2023.3.0" />
|
||||||
<PackageReference Include="LiteDB" Version="5.0.17" />
|
|
||||||
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" />
|
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
||||||
<PackageReference Include="RGB.NET.Core" Version="$(RGBDotNetVersion)" />
|
<PackageReference Include="RGB.NET.Core" Version="2.0.4-prerelease.1" />
|
||||||
<PackageReference Include="RGB.NET.Layout" Version="$(RGBDotNetVersion)" />
|
<PackageReference Include="RGB.NET.Layout" Version="2.0.4-prerelease.1" />
|
||||||
<PackageReference Include="RGB.NET.Presets" Version="$(RGBDotNetVersion)" />
|
<PackageReference Include="RGB.NET.Presets" Version="2.0.4-prerelease.1" />
|
||||||
<PackageReference Include="Serilog" Version="3.0.1" />
|
<PackageReference Include="Serilog.Sinks.Console" Version="5.0.1" />
|
||||||
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
|
|
||||||
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" />
|
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" />
|
||||||
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
<PackageReference Include="Serilog.Sinks.File" Version="5.0.0" />
|
||||||
<PackageReference Include="SkiaSharp" Version="$(SkiaSharpVersion)" />
|
<PackageReference Include="SkiaSharp" Version="2.88.7" />
|
||||||
<PackageReference Include="System.Buffers" Version="4.5.1" />
|
|
||||||
<PackageReference Include="System.IO.FileSystem.AccessControl" Version="5.0.0" />
|
|
||||||
<PackageReference Include="System.Numerics.Vectors" Version="4.5.0" />
|
|
||||||
<PackageReference Include="System.ValueTuple" Version="4.5.0" />
|
|
||||||
<PackageReference Include="Unosquare.Swan.Lite" Version="3.1.0" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|||||||
@ -47,6 +47,7 @@ public static class Constants
|
|||||||
/// The full path to the Artemis logs folder
|
/// The full path to the Artemis logs folder
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly string LogsFolder = Path.Combine(DataFolder, "Logs");
|
public static readonly string LogsFolder = Path.Combine(DataFolder, "Logs");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The full path to the Artemis logs folder
|
/// The full path to the Artemis logs folder
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -61,6 +62,11 @@ public static class Constants
|
|||||||
/// The full path to the Artemis user layouts folder
|
/// The full path to the Artemis user layouts folder
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly string LayoutsFolder = Path.Combine(DataFolder, "User Layouts");
|
public static readonly string LayoutsFolder = Path.Combine(DataFolder, "User Layouts");
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The full path to the Artemis user layouts folder
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string WorkshopFolder = Path.Combine(DataFolder, "workshop");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current API version for plugins
|
/// The current API version for plugins
|
||||||
@ -71,9 +77,9 @@ public static class Constants
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current version of the application
|
/// The current version of the application
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly string CurrentVersion = CoreAssembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()!.InformationalVersion != "1.0.0"
|
public static readonly string CurrentVersion = CoreAssembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()!.InformationalVersion.StartsWith("1.0.0")
|
||||||
? CoreAssembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()!.InformationalVersion
|
? "local"
|
||||||
: "local";
|
: CoreAssembly.GetCustomAttribute<AssemblyInformationalVersionAttribute>()!.InformationalVersion;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The plugin info used by core components of Artemis
|
/// The plugin info used by core components of Artemis
|
||||||
@ -151,8 +157,8 @@ public static class Constants
|
|||||||
public static ReadOnlyCollection<string> StartupArguments { get; set; } = null!;
|
public static ReadOnlyCollection<string> StartupArguments { get; set; } = null!;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the graphics context to be used for rendering by SkiaSharp. Can be set via
|
/// Gets the graphics context to be used for rendering by SkiaSharp.
|
||||||
/// <see cref="IRgbService.UpdateGraphicsContext" />.
|
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static IManagedGraphicsContext? ManagedGraphicsContext { get; internal set; }
|
public static IManagedGraphicsContext? ManagedGraphicsContext { get; internal set; }
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -2,6 +2,7 @@ using System;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Artemis.Core.DryIoc.Factories;
|
using Artemis.Core.DryIoc.Factories;
|
||||||
|
using Artemis.Core.Providers;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
using Artemis.Storage;
|
using Artemis.Storage;
|
||||||
using Artemis.Storage.Migrations.Interfaces;
|
using Artemis.Storage.Migrations.Interfaces;
|
||||||
@ -35,7 +36,8 @@ public static class ContainerExtensions
|
|||||||
|
|
||||||
// Bind migrations
|
// Bind migrations
|
||||||
container.RegisterMany(storageAssembly, type => type.IsAssignableTo<IStorageMigration>(), Reuse.Singleton, nonPublicServiceTypes: true);
|
container.RegisterMany(storageAssembly, type => type.IsAssignableTo<IStorageMigration>(), Reuse.Singleton, nonPublicServiceTypes: true);
|
||||||
|
|
||||||
|
container.RegisterMany(coreAssembly, type => type.IsAssignableTo<ILayoutProvider>(), Reuse.Singleton);
|
||||||
container.Register<IPluginSettingsFactory, PluginSettingsFactory>(Reuse.Singleton);
|
container.Register<IPluginSettingsFactory, PluginSettingsFactory>(Reuse.Singleton);
|
||||||
container.Register(Made.Of(_ => ServiceInfo.Of<IPluginSettingsFactory>(), f => f.CreatePluginSettings(Arg.Index<Type>(0)), r => r.Parent.ImplementationType));
|
container.Register(Made.Of(_ => ServiceInfo.Of<IPluginSettingsFactory>(), f => f.CreatePluginSettings(Arg.Index<Type>(0)), r => r.Parent.ImplementationType));
|
||||||
container.Register<ILoggerFactory, LoggerFactory>(Reuse.Singleton);
|
container.Register<ILoggerFactory, LoggerFactory>(Reuse.Singleton);
|
||||||
|
|||||||
@ -1,31 +0,0 @@
|
|||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace Artemis.Core;
|
|
||||||
|
|
||||||
internal static class DirectoryInfoExtensions
|
|
||||||
{
|
|
||||||
public static void CopyFilesRecursively(this DirectoryInfo source, DirectoryInfo target)
|
|
||||||
{
|
|
||||||
foreach (DirectoryInfo dir in source.GetDirectories())
|
|
||||||
CopyFilesRecursively(dir, target.CreateSubdirectory(dir.Name));
|
|
||||||
foreach (FileInfo file in source.GetFiles())
|
|
||||||
file.CopyTo(Path.Combine(target.FullName, file.Name));
|
|
||||||
}
|
|
||||||
|
|
||||||
public static void DeleteRecursively(this DirectoryInfo baseDir)
|
|
||||||
{
|
|
||||||
if (!baseDir.Exists)
|
|
||||||
return;
|
|
||||||
|
|
||||||
foreach (DirectoryInfo dir in baseDir.EnumerateDirectories())
|
|
||||||
DeleteRecursively(dir);
|
|
||||||
FileInfo[] files = baseDir.GetFiles();
|
|
||||||
foreach (FileInfo file in files)
|
|
||||||
{
|
|
||||||
file.IsReadOnly = false;
|
|
||||||
file.Delete();
|
|
||||||
}
|
|
||||||
|
|
||||||
baseDir.Delete();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -23,7 +23,6 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable
|
|||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
private Hotkey? _enableHotkey;
|
private Hotkey? _enableHotkey;
|
||||||
private ProfileConfigurationHotkeyMode _hotkeyMode;
|
private ProfileConfigurationHotkeyMode _hotkeyMode;
|
||||||
private bool _isBeingEdited;
|
|
||||||
private bool _isMissingModule;
|
private bool _isMissingModule;
|
||||||
private bool _isSuspended;
|
private bool _isSuspended;
|
||||||
private bool _fadeInAndOut;
|
private bool _fadeInAndOut;
|
||||||
|
|||||||
@ -2,9 +2,10 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Artemis.Core.DeviceProviders;
|
using Artemis.Core.DeviceProviders;
|
||||||
|
using Artemis.Core.Providers;
|
||||||
|
using Artemis.Core.Services;
|
||||||
using Artemis.Storage.Entities.Surface;
|
using Artemis.Storage.Entities.Surface;
|
||||||
using RGB.NET.Core;
|
using RGB.NET.Core;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
@ -45,6 +46,7 @@ public class ArtemisDevice : CorePropertyChanged
|
|||||||
InputIdentifiers = new List<ArtemisDeviceInputIdentifier>();
|
InputIdentifiers = new List<ArtemisDeviceInputIdentifier>();
|
||||||
InputMappings = new Dictionary<ArtemisLed, ArtemisLed>();
|
InputMappings = new Dictionary<ArtemisLed, ArtemisLed>();
|
||||||
Categories = new HashSet<DeviceCategory>();
|
Categories = new HashSet<DeviceCategory>();
|
||||||
|
LayoutSelection = new LayoutSelection {Type = DefaultLayoutProvider.LayoutType};
|
||||||
|
|
||||||
RgbDevice.ColorCorrections.Clear();
|
RgbDevice.ColorCorrections.Clear();
|
||||||
RgbDevice.ColorCorrections.Add(new ScaleColorCorrection(this));
|
RgbDevice.ColorCorrections.Add(new ScaleColorCorrection(this));
|
||||||
@ -73,6 +75,7 @@ public class ArtemisDevice : CorePropertyChanged
|
|||||||
InputIdentifiers = new List<ArtemisDeviceInputIdentifier>();
|
InputIdentifiers = new List<ArtemisDeviceInputIdentifier>();
|
||||||
InputMappings = new Dictionary<ArtemisLed, ArtemisLed>();
|
InputMappings = new Dictionary<ArtemisLed, ArtemisLed>();
|
||||||
Categories = new HashSet<DeviceCategory>();
|
Categories = new HashSet<DeviceCategory>();
|
||||||
|
LayoutSelection = new LayoutSelection {Type = DefaultLayoutProvider.LayoutType};
|
||||||
|
|
||||||
foreach (DeviceInputIdentifierEntity identifierEntity in DeviceEntity.InputIdentifiers)
|
foreach (DeviceInputIdentifierEntity identifierEntity in DeviceEntity.InputIdentifiers)
|
||||||
InputIdentifiers.Add(new ArtemisDeviceInputIdentifier(identifierEntity.InputProvider, identifierEntity.Identifier));
|
InputIdentifiers.Add(new ArtemisDeviceInputIdentifier(identifierEntity.InputProvider, identifierEntity.Identifier));
|
||||||
@ -152,6 +155,8 @@ public class ArtemisDevice : CorePropertyChanged
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public HashSet<DeviceCategory> Categories { get; }
|
public HashSet<DeviceCategory> Categories { get; }
|
||||||
|
|
||||||
|
public LayoutSelection LayoutSelection { get; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the X-position of the device
|
/// Gets or sets the X-position of the device
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -266,7 +271,7 @@ public class ArtemisDevice : CorePropertyChanged
|
|||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a boolean indicating whether this devices is enabled or not
|
/// Gets a boolean indicating whether this devices is enabled or not
|
||||||
/// <para>Note: To enable/disable a device use the methods provided by <see cref="IRgbService" /></para>
|
/// <para>Note: To enable/disable a device use the methods provided by <see cref="IDeviceService" /></para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsEnabled
|
public bool IsEnabled
|
||||||
{
|
{
|
||||||
@ -292,19 +297,6 @@ public class ArtemisDevice : CorePropertyChanged
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets a boolean indicating whether falling back to default layouts is enabled or not
|
|
||||||
/// </summary>
|
|
||||||
public bool DisableDefaultLayout
|
|
||||||
{
|
|
||||||
get => DeviceEntity.DisableDefaultLayout;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
DeviceEntity.DisableDefaultLayout = value;
|
|
||||||
OnPropertyChanged(nameof(DisableDefaultLayout));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the logical layout of the device e.g. DE, UK or US.
|
/// Gets or sets the logical layout of the device e.g. DE, UK or US.
|
||||||
/// <para>Only applicable to keyboards</para>
|
/// <para>Only applicable to keyboards</para>
|
||||||
@ -319,20 +311,6 @@ public class ArtemisDevice : CorePropertyChanged
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets or sets the path of the custom layout to load when calling <see cref="IRgbService.ApplyBestDeviceLayout" />
|
|
||||||
/// for this device
|
|
||||||
/// </summary>
|
|
||||||
public string? CustomLayoutPath
|
|
||||||
{
|
|
||||||
get => DeviceEntity.CustomLayoutPath;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
DeviceEntity.CustomLayoutPath = value;
|
|
||||||
OnPropertyChanged(nameof(CustomLayoutPath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the layout of the device expanded with Artemis-specific data
|
/// Gets the layout of the device expanded with Artemis-specific data
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -380,40 +358,6 @@ public class ArtemisDevice : CorePropertyChanged
|
|||||||
return artemisLed;
|
return artemisLed;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Returns the most preferred device layout for this device.
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>The most preferred device layout for this device.</returns>
|
|
||||||
public ArtemisLayout? GetBestDeviceLayout()
|
|
||||||
{
|
|
||||||
ArtemisLayout? layout;
|
|
||||||
|
|
||||||
// Configured layout path takes precedence over all other options
|
|
||||||
if (CustomLayoutPath != null)
|
|
||||||
{
|
|
||||||
layout = new ArtemisLayout(CustomLayoutPath, LayoutSource.Configured);
|
|
||||||
if (layout.IsValid)
|
|
||||||
return layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Look for a layout provided by the user
|
|
||||||
layout = DeviceProvider.LoadUserLayout(this);
|
|
||||||
if (layout.IsValid)
|
|
||||||
return layout;
|
|
||||||
|
|
||||||
if (DisableDefaultLayout)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
// Look for a layout provided by the plugin
|
|
||||||
layout = DeviceProvider.LoadLayout(this);
|
|
||||||
if (layout.IsValid)
|
|
||||||
return layout;
|
|
||||||
|
|
||||||
// Finally fall back to a default layout
|
|
||||||
layout = ArtemisLayout.GetDefaultLayout(this);
|
|
||||||
return layout;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Occurs when the underlying RGB.NET device was updated
|
/// Occurs when the underlying RGB.NET device was updated
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -454,14 +398,6 @@ public class ArtemisDevice : CorePropertyChanged
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Invokes the <see cref="DeviceUpdated" /> event
|
|
||||||
/// </summary>
|
|
||||||
protected virtual void OnDeviceUpdated()
|
|
||||||
{
|
|
||||||
DeviceUpdated?.Invoke(this, EventArgs.Empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Applies the provided layout to the device
|
/// Applies the provided layout to the device
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -474,13 +410,13 @@ public class ArtemisDevice : CorePropertyChanged
|
|||||||
/// A boolean indicating whether to remove excess LEDs present in the device but missing
|
/// A boolean indicating whether to remove excess LEDs present in the device but missing
|
||||||
/// in the layout
|
/// in the layout
|
||||||
/// </param>
|
/// </param>
|
||||||
internal void ApplyLayout(ArtemisLayout? layout, bool createMissingLeds, bool removeExcessiveLeds)
|
public void ApplyLayout(ArtemisLayout? layout, bool createMissingLeds, bool removeExcessiveLeds)
|
||||||
{
|
{
|
||||||
if (layout != null && layout.IsValid && createMissingLeds && !DeviceProvider.CreateMissingLedsSupported)
|
if (layout != null && layout.IsValid && createMissingLeds && !DeviceProvider.CreateMissingLedsSupported)
|
||||||
throw new ArtemisCoreException($"Cannot apply layout with {nameof(createMissingLeds)} set to true because the device provider does not support it");
|
throw new ArtemisCoreException($"Cannot apply layout with {nameof(createMissingLeds)} set to true because the device provider does not support it");
|
||||||
if (layout != null && layout.IsValid && removeExcessiveLeds && !DeviceProvider.RemoveExcessiveLedsSupported)
|
if (layout != null && layout.IsValid && removeExcessiveLeds && !DeviceProvider.RemoveExcessiveLedsSupported)
|
||||||
throw new ArtemisCoreException($"Cannot apply layout with {nameof(removeExcessiveLeds)} set to true because the device provider does not support it");
|
throw new ArtemisCoreException($"Cannot apply layout with {nameof(removeExcessiveLeds)} set to true because the device provider does not support it");
|
||||||
|
|
||||||
// Always clear the current layout
|
// Always clear the current layout
|
||||||
ClearLayout();
|
ClearLayout();
|
||||||
|
|
||||||
@ -501,6 +437,14 @@ public class ArtemisDevice : CorePropertyChanged
|
|||||||
CalculateRenderProperties();
|
CalculateRenderProperties();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Invokes the <see cref="DeviceUpdated" /> event
|
||||||
|
/// </summary>
|
||||||
|
protected virtual void OnDeviceUpdated()
|
||||||
|
{
|
||||||
|
DeviceUpdated?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
private void ClearLayout()
|
private void ClearLayout()
|
||||||
{
|
{
|
||||||
if (Layout == null)
|
if (Layout == null)
|
||||||
@ -533,6 +477,9 @@ public class ArtemisDevice : CorePropertyChanged
|
|||||||
DeviceEntity.Categories.Clear();
|
DeviceEntity.Categories.Clear();
|
||||||
foreach (DeviceCategory deviceCategory in Categories)
|
foreach (DeviceCategory deviceCategory in Categories)
|
||||||
DeviceEntity.Categories.Add((int) deviceCategory);
|
DeviceEntity.Categories.Add((int) deviceCategory);
|
||||||
|
|
||||||
|
DeviceEntity.LayoutType = LayoutSelection.Type;
|
||||||
|
DeviceEntity.LayoutParameter = LayoutSelection.Parameter;
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Load()
|
internal void Load()
|
||||||
@ -547,6 +494,9 @@ public class ArtemisDevice : CorePropertyChanged
|
|||||||
if (!Categories.Any())
|
if (!Categories.Any())
|
||||||
ApplyDefaultCategories();
|
ApplyDefaultCategories();
|
||||||
|
|
||||||
|
LayoutSelection.Type = DeviceEntity.LayoutType;
|
||||||
|
LayoutSelection.Parameter = DeviceEntity.LayoutParameter;
|
||||||
|
|
||||||
LoadInputMappings();
|
LoadInputMappings();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -572,7 +522,7 @@ public class ArtemisDevice : CorePropertyChanged
|
|||||||
{
|
{
|
||||||
Leds = RgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly();
|
Leds = RgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly();
|
||||||
LedIds = new ReadOnlyDictionary<LedId, ArtemisLed>(Leds.ToDictionary(l => l.RgbLed.Id, l => l));
|
LedIds = new ReadOnlyDictionary<LedId, ArtemisLed>(Leds.ToDictionary(l => l.RgbLed.Id, l => l));
|
||||||
|
|
||||||
if (loadInputMappings)
|
if (loadInputMappings)
|
||||||
LoadInputMappings();
|
LoadInputMappings();
|
||||||
}
|
}
|
||||||
|
|||||||
@ -12,17 +12,18 @@ namespace Artemis.Core;
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public class ArtemisLayout
|
public class ArtemisLayout
|
||||||
{
|
{
|
||||||
|
private static readonly string DefaultLayoutPath = Path.Combine(Constants.ApplicationFolder, "DefaultLayouts", "Artemis");
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new instance of the <see cref="ArtemisLayout" /> class
|
/// Creates a new instance of the <see cref="ArtemisLayout" /> class
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="filePath">The path of the layout XML file</param>
|
/// <param name="filePath">The path of the layout XML file</param>
|
||||||
/// <param name="source">The source from where this layout is being loaded</param>
|
public ArtemisLayout(string filePath)
|
||||||
public ArtemisLayout(string filePath, LayoutSource source)
|
|
||||||
{
|
{
|
||||||
FilePath = filePath;
|
FilePath = filePath;
|
||||||
Source = source;
|
|
||||||
Leds = new List<ArtemisLedLayout>();
|
Leds = new List<ArtemisLedLayout>();
|
||||||
|
IsDefaultLayout = filePath.StartsWith(DefaultLayoutPath);
|
||||||
|
|
||||||
LoadLayout();
|
LoadLayout();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -31,11 +32,6 @@ public class ArtemisLayout
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public string FilePath { get; }
|
public string FilePath { get; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the source from where this layout was loaded
|
|
||||||
/// </summary>
|
|
||||||
public LayoutSource Source { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets a boolean indicating whether a valid layout was loaded
|
/// Gets a boolean indicating whether a valid layout was loaded
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -61,6 +57,8 @@ public class ArtemisLayout
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public LayoutCustomDeviceData LayoutCustomDeviceData { get; private set; } = null!;
|
public LayoutCustomDeviceData LayoutCustomDeviceData { get; private set; } = null!;
|
||||||
|
|
||||||
|
public bool IsDefaultLayout { get; private set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Applies the layout to the provided device
|
/// Applies the layout to the provided device
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -121,29 +119,28 @@ public class ArtemisLayout
|
|||||||
|
|
||||||
internal static ArtemisLayout? GetDefaultLayout(ArtemisDevice device)
|
internal static ArtemisLayout? GetDefaultLayout(ArtemisDevice device)
|
||||||
{
|
{
|
||||||
string layoutFolder = Path.Combine(Constants.ApplicationFolder, "DefaultLayouts", "Artemis");
|
|
||||||
if (device.DeviceType == RGBDeviceType.Keyboard)
|
if (device.DeviceType == RGBDeviceType.Keyboard)
|
||||||
{
|
{
|
||||||
// XL layout is defined by its programmable macro keys
|
// XL layout is defined by its programmable macro keys
|
||||||
if (device.Leds.Any(l => l.RgbLed.Id >= LedId.Keyboard_Programmable1 && l.RgbLed.Id <= LedId.Keyboard_Programmable32))
|
if (device.Leds.Any(l => l.RgbLed.Id >= LedId.Keyboard_Programmable1 && l.RgbLed.Id <= LedId.Keyboard_Programmable32))
|
||||||
{
|
{
|
||||||
if (device.PhysicalLayout == KeyboardLayoutType.ANSI)
|
if (device.PhysicalLayout == KeyboardLayoutType.ANSI)
|
||||||
return new ArtemisLayout(Path.Combine(layoutFolder, "Keyboard", "Artemis XL keyboard-ANSI.xml"), LayoutSource.Default);
|
return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Keyboard", "Artemis XL keyboard-ANSI.xml"));
|
||||||
return new ArtemisLayout(Path.Combine(layoutFolder, "Keyboard", "Artemis XL keyboard-ISO.xml"), LayoutSource.Default);
|
return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Keyboard", "Artemis XL keyboard-ISO.xml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// L layout is defined by its numpad
|
// L layout is defined by its numpad
|
||||||
if (device.Leds.Any(l => l.RgbLed.Id >= LedId.Keyboard_NumLock && l.RgbLed.Id <= LedId.Keyboard_NumPeriodAndDelete))
|
if (device.Leds.Any(l => l.RgbLed.Id >= LedId.Keyboard_NumLock && l.RgbLed.Id <= LedId.Keyboard_NumPeriodAndDelete))
|
||||||
{
|
{
|
||||||
if (device.PhysicalLayout == KeyboardLayoutType.ANSI)
|
if (device.PhysicalLayout == KeyboardLayoutType.ANSI)
|
||||||
return new ArtemisLayout(Path.Combine(layoutFolder + "Keyboard", "Artemis L keyboard-ANSI.xml"), LayoutSource.Default);
|
return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Keyboard", "Artemis L keyboard-ANSI.xml"));
|
||||||
return new ArtemisLayout(Path.Combine(layoutFolder + "Keyboard", "Artemis L keyboard-ISO.xml"), LayoutSource.Default);
|
return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Keyboard", "Artemis L keyboard-ISO.xml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// No numpad will result in TKL
|
// No numpad will result in TKL
|
||||||
if (device.PhysicalLayout == KeyboardLayoutType.ANSI)
|
if (device.PhysicalLayout == KeyboardLayoutType.ANSI)
|
||||||
return new ArtemisLayout(Path.Combine(layoutFolder + "Keyboard", "Artemis TKL keyboard-ANSI.xml"), LayoutSource.Default);
|
return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Keyboard", "Artemis TKL keyboard-ANSI.xml"));
|
||||||
return new ArtemisLayout(Path.Combine(layoutFolder + "Keyboard", "Artemis TKL keyboard-ISO.xml"), LayoutSource.Default);
|
return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Keyboard", "Artemis TKL keyboard-ISO.xml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
// if (device.DeviceType == RGBDeviceType.Mouse)
|
// if (device.DeviceType == RGBDeviceType.Mouse)
|
||||||
@ -151,21 +148,21 @@ public class ArtemisLayout
|
|||||||
// if (device.Leds.Count == 1)
|
// if (device.Leds.Count == 1)
|
||||||
// {
|
// {
|
||||||
// if (device.Leds.Any(l => l.RgbLed.Id == LedId.Logo))
|
// if (device.Leds.Any(l => l.RgbLed.Id == LedId.Logo))
|
||||||
// return new ArtemisLayout(Path.Combine(layoutFolder + "Mouse", "1 LED mouse logo.xml"), LayoutSource.Default);
|
// return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Mouse", "1 LED mouse logo.xml"), LayoutSource.Default);
|
||||||
// return new ArtemisLayout(Path.Combine(layoutFolder + "Mouse", "1 LED mouse.xml"), LayoutSource.Default);
|
// return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Mouse", "1 LED mouse.xml"), LayoutSource.Default);
|
||||||
// }
|
// }
|
||||||
// if (device.Leds.Any(l => l.RgbLed.Id == LedId.Logo))
|
// if (device.Leds.Any(l => l.RgbLed.Id == LedId.Logo))
|
||||||
// return new ArtemisLayout(Path.Combine(layoutFolder + "Mouse", "4 LED mouse logo.xml"), LayoutSource.Default);
|
// return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Mouse", "4 LED mouse logo.xml"), LayoutSource.Default);
|
||||||
// return new ArtemisLayout(Path.Combine(layoutFolder + "Mouse", "4 LED mouse.xml"), LayoutSource.Default);
|
// return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Mouse", "4 LED mouse.xml"), LayoutSource.Default);
|
||||||
// }
|
// }
|
||||||
|
|
||||||
if (device.DeviceType == RGBDeviceType.Headset)
|
if (device.DeviceType == RGBDeviceType.Headset)
|
||||||
{
|
{
|
||||||
if (device.Leds.Count == 1)
|
if (device.Leds.Count == 1)
|
||||||
return new ArtemisLayout(Path.Combine(layoutFolder + "Headset", "Artemis 1 LED headset.xml"), LayoutSource.Default);
|
return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Headset", "Artemis 1 LED headset.xml"));
|
||||||
if (device.Leds.Count == 2)
|
if (device.Leds.Count == 2)
|
||||||
return new ArtemisLayout(Path.Combine(layoutFolder + "Headset", "Artemis 2 LED headset.xml"), LayoutSource.Default);
|
return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Headset", "Artemis 2 LED headset.xml"));
|
||||||
return new ArtemisLayout(Path.Combine(layoutFolder + "Headset", "Artemis 4 LED headset.xml"), LayoutSource.Default);
|
return new ArtemisLayout(Path.Combine(DefaultLayoutPath, "Headset", "Artemis 4 LED headset.xml"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
@ -206,30 +203,10 @@ public class ArtemisLayout
|
|||||||
else
|
else
|
||||||
Image = null;
|
Image = null;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <inheritdoc />
|
||||||
/// Represents a source from where a layout came
|
public override string ToString()
|
||||||
/// </summary>
|
{
|
||||||
public enum LayoutSource
|
return FilePath;
|
||||||
{
|
}
|
||||||
/// <summary>
|
|
||||||
/// A layout loaded from config
|
|
||||||
/// </summary>
|
|
||||||
Configured,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A layout loaded from the user layout folder
|
|
||||||
/// </summary>
|
|
||||||
User,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A layout loaded from the plugin folder
|
|
||||||
/// </summary>
|
|
||||||
Plugin,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// A default layout loaded as a fallback option
|
|
||||||
/// </summary>
|
|
||||||
Default
|
|
||||||
}
|
}
|
||||||
@ -15,6 +15,11 @@ public class ArtemisLedLayout
|
|||||||
DeviceLayout = deviceLayout;
|
DeviceLayout = deviceLayout;
|
||||||
RgbLayout = led;
|
RgbLayout = led;
|
||||||
LayoutCustomLedData = (LayoutCustomLedData?) led.CustomData ?? new LayoutCustomLedData();
|
LayoutCustomLedData = (LayoutCustomLedData?) led.CustomData ?? new LayoutCustomLedData();
|
||||||
|
|
||||||
|
// Default to the first logical layout for images
|
||||||
|
LayoutCustomLedDataLogicalLayout? defaultLogicalLayout = LayoutCustomLedData.LogicalLayouts?.FirstOrDefault();
|
||||||
|
if (defaultLogicalLayout != null)
|
||||||
|
ApplyLogicalLayout(defaultLogicalLayout);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -54,7 +59,17 @@ public class ArtemisLedLayout
|
|||||||
.ThenBy(l => l.Name == null)
|
.ThenBy(l => l.Name == null)
|
||||||
.First();
|
.First();
|
||||||
|
|
||||||
|
ApplyLogicalLayout(logicalLayout);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyLogicalLayout(LayoutCustomLedDataLogicalLayout logicalLayout)
|
||||||
|
{
|
||||||
|
string? layoutDirectory = Path.GetDirectoryName(DeviceLayout.FilePath);
|
||||||
|
|
||||||
LogicalName = logicalLayout.Name;
|
LogicalName = logicalLayout.Name;
|
||||||
Image = new Uri(Path.Combine(Path.GetDirectoryName(DeviceLayout.FilePath)!, logicalLayout.Image!), UriKind.Absolute);
|
if (layoutDirectory != null && logicalLayout.Image != null)
|
||||||
|
Image = new Uri(Path.Combine(layoutDirectory, logicalLayout.Image!), UriKind.Absolute);
|
||||||
|
else
|
||||||
|
Image = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
28
src/Artemis.Core/Models/Surface/LayoutSelection.cs
Normal file
28
src/Artemis.Core/Models/Surface/LayoutSelection.cs
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
namespace Artemis.Core;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a reference to a layout for a device.
|
||||||
|
/// </summary>
|
||||||
|
public class LayoutSelection : CorePropertyChanged
|
||||||
|
{
|
||||||
|
private string? _type;
|
||||||
|
private string? _parameter;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets what kind of layout reference this is.
|
||||||
|
/// </summary>
|
||||||
|
public string? Type
|
||||||
|
{
|
||||||
|
get => _type;
|
||||||
|
set => SetAndNotify(ref _type, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the parameter of the layout reference, such as a file path of workshop entry ID.
|
||||||
|
/// </summary>
|
||||||
|
public string? Parameter
|
||||||
|
{
|
||||||
|
get => _parameter;
|
||||||
|
set => SetAndNotify(ref _parameter, value);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -62,7 +62,7 @@ public abstract class DeviceProvider : PluginFeature
|
|||||||
device.DeviceType.ToString(),
|
device.DeviceType.ToString(),
|
||||||
GetDeviceLayoutName(device)
|
GetDeviceLayoutName(device)
|
||||||
);
|
);
|
||||||
return new ArtemisLayout(filePath, LayoutSource.Plugin);
|
return new ArtemisLayout(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -79,7 +79,7 @@ public abstract class DeviceProvider : PluginFeature
|
|||||||
device.DeviceType.ToString(),
|
device.DeviceType.ToString(),
|
||||||
GetDeviceLayoutName(device)
|
GetDeviceLayoutName(device)
|
||||||
);
|
);
|
||||||
return new ArtemisLayout(filePath, LayoutSource.User);
|
return new ArtemisLayout(filePath);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
37
src/Artemis.Core/Providers/CustomPathLayoutProvider.cs
Normal file
37
src/Artemis.Core/Providers/CustomPathLayoutProvider.cs
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
namespace Artemis.Core.Providers;
|
||||||
|
|
||||||
|
public class CustomPathLayoutProvider : ILayoutProvider
|
||||||
|
{
|
||||||
|
public static string LayoutType = "CustomPath";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ArtemisLayout? GetDeviceLayout(ArtemisDevice device)
|
||||||
|
{
|
||||||
|
if (device.LayoutSelection.Parameter == null)
|
||||||
|
return null;
|
||||||
|
return new ArtemisLayout(device.LayoutSelection.Parameter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void ApplyLayout(ArtemisDevice device, ArtemisLayout layout)
|
||||||
|
{
|
||||||
|
device.ApplyLayout(layout, device.DeviceProvider.CreateMissingLedsSupported, device.DeviceProvider.RemoveExcessiveLedsSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool IsMatch(ArtemisDevice device)
|
||||||
|
{
|
||||||
|
return device.LayoutSelection.Type == LayoutType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configures the provided device to use this layout provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="device">The device to apply the provider to.</param>
|
||||||
|
/// <param name="path">The path to the custom layout.</param>
|
||||||
|
public void ConfigureDevice(ArtemisDevice device, string? path)
|
||||||
|
{
|
||||||
|
device.LayoutSelection.Type = LayoutType;
|
||||||
|
device.LayoutSelection.Parameter = path;
|
||||||
|
}
|
||||||
|
}
|
||||||
41
src/Artemis.Core/Providers/DefaultLayoutProvider.cs
Normal file
41
src/Artemis.Core/Providers/DefaultLayoutProvider.cs
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
namespace Artemis.Core.Providers;
|
||||||
|
|
||||||
|
public class DefaultLayoutProvider : ILayoutProvider
|
||||||
|
{
|
||||||
|
public static string LayoutType = "Default";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ArtemisLayout? GetDeviceLayout(ArtemisDevice device)
|
||||||
|
{
|
||||||
|
// Look for a layout provided by the plugin
|
||||||
|
ArtemisLayout layout = device.DeviceProvider.LoadLayout(device);
|
||||||
|
|
||||||
|
// Finally fall back to a default layout
|
||||||
|
return layout.IsValid ? layout : ArtemisLayout.GetDefaultLayout(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void ApplyLayout(ArtemisDevice device, ArtemisLayout layout)
|
||||||
|
{
|
||||||
|
if (layout.IsDefaultLayout)
|
||||||
|
device.ApplyLayout(layout, false, false);
|
||||||
|
else
|
||||||
|
device.ApplyLayout(layout, device.DeviceProvider.CreateMissingLedsSupported, device.DeviceProvider.RemoveExcessiveLedsSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool IsMatch(ArtemisDevice device)
|
||||||
|
{
|
||||||
|
return device.LayoutSelection.Type == LayoutType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configures the provided device to use this layout provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="device">The device to apply the provider to.</param>
|
||||||
|
public void ConfigureDevice(ArtemisDevice device)
|
||||||
|
{
|
||||||
|
device.LayoutSelection.Type = LayoutType;
|
||||||
|
device.LayoutSelection.Parameter = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
17
src/Artemis.Core/Providers/Interfaces/ILayoutProvider.cs
Normal file
17
src/Artemis.Core/Providers/Interfaces/ILayoutProvider.cs
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
namespace Artemis.Core.Providers;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents a class that can provide Artemis layouts for devices.
|
||||||
|
/// </summary>
|
||||||
|
public interface ILayoutProvider
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// If available, loads an Artemis layout for the provided device.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="device">The device to load the layout for.</param>
|
||||||
|
/// <returns>The resulting layout if one was available; otherwise <see langword="null" />.</returns>
|
||||||
|
ArtemisLayout? GetDeviceLayout(ArtemisDevice device);
|
||||||
|
|
||||||
|
void ApplyLayout(ArtemisDevice device, ArtemisLayout layout);
|
||||||
|
bool IsMatch(ArtemisDevice device);
|
||||||
|
}
|
||||||
34
src/Artemis.Core/Providers/NoneLayoutProvider.cs
Normal file
34
src/Artemis.Core/Providers/NoneLayoutProvider.cs
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
namespace Artemis.Core.Providers;
|
||||||
|
|
||||||
|
public class NoneLayoutProvider : ILayoutProvider
|
||||||
|
{
|
||||||
|
public static string LayoutType = "None";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ArtemisLayout? GetDeviceLayout(ArtemisDevice device)
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void ApplyLayout(ArtemisDevice device, ArtemisLayout layout)
|
||||||
|
{
|
||||||
|
device.ApplyLayout(null, false, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public bool IsMatch(ArtemisDevice device)
|
||||||
|
{
|
||||||
|
return device.LayoutSelection.Type == LayoutType;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Configures the provided device to use this layout provider.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="device">The device to apply the provider to.</param>
|
||||||
|
public void ConfigureDevice(ArtemisDevice device)
|
||||||
|
{
|
||||||
|
device.LayoutSelection.Type = LayoutType;
|
||||||
|
device.LayoutSelection.Parameter = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -4,9 +4,11 @@ using System.Collections.ObjectModel;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core.DeviceProviders;
|
using Artemis.Core.DeviceProviders;
|
||||||
|
using Artemis.Core.Providers;
|
||||||
using Artemis.Core.Services.Models;
|
using Artemis.Core.Services.Models;
|
||||||
using Artemis.Storage.Entities.Surface;
|
using Artemis.Storage.Entities.Surface;
|
||||||
using Artemis.Storage.Repositories.Interfaces;
|
using Artemis.Storage.Repositories.Interfaces;
|
||||||
|
using DryIoc;
|
||||||
using RGB.NET.Core;
|
using RGB.NET.Core;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
|
|
||||||
@ -18,15 +20,21 @@ internal class DeviceService : IDeviceService
|
|||||||
private readonly IPluginManagementService _pluginManagementService;
|
private readonly IPluginManagementService _pluginManagementService;
|
||||||
private readonly IDeviceRepository _deviceRepository;
|
private readonly IDeviceRepository _deviceRepository;
|
||||||
private readonly Lazy<IRenderService> _renderService;
|
private readonly Lazy<IRenderService> _renderService;
|
||||||
|
private readonly Func<List<ILayoutProvider>> _getLayoutProviders;
|
||||||
private readonly List<ArtemisDevice> _enabledDevices = new();
|
private readonly List<ArtemisDevice> _enabledDevices = new();
|
||||||
private readonly List<ArtemisDevice> _devices = new();
|
private readonly List<ArtemisDevice> _devices = new();
|
||||||
|
|
||||||
public DeviceService(ILogger logger, IPluginManagementService pluginManagementService, IDeviceRepository deviceRepository, Lazy<IRenderService> renderService)
|
public DeviceService(ILogger logger,
|
||||||
|
IPluginManagementService pluginManagementService,
|
||||||
|
IDeviceRepository deviceRepository,
|
||||||
|
Lazy<IRenderService> renderService,
|
||||||
|
Func<List<ILayoutProvider>> getLayoutProviders)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_pluginManagementService = pluginManagementService;
|
_pluginManagementService = pluginManagementService;
|
||||||
_deviceRepository = deviceRepository;
|
_deviceRepository = deviceRepository;
|
||||||
_renderService = renderService;
|
_renderService = renderService;
|
||||||
|
_getLayoutProviders = getLayoutProviders;
|
||||||
|
|
||||||
EnabledDevices = new ReadOnlyCollection<ArtemisDevice>(_enabledDevices);
|
EnabledDevices = new ReadOnlyCollection<ArtemisDevice>(_enabledDevices);
|
||||||
Devices = new ReadOnlyCollection<ArtemisDevice>(_devices);
|
Devices = new ReadOnlyCollection<ArtemisDevice>(_devices);
|
||||||
@ -157,12 +165,30 @@ internal class DeviceService : IDeviceService
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void ApplyDeviceLayout(ArtemisDevice device, ArtemisLayout? layout)
|
public void LoadDeviceLayout(ArtemisDevice device)
|
||||||
{
|
{
|
||||||
if (layout == null || layout.Source == LayoutSource.Default)
|
ILayoutProvider? provider = _getLayoutProviders().FirstOrDefault(p => p.IsMatch(device));
|
||||||
device.ApplyLayout(layout, false, false);
|
if (provider == null)
|
||||||
else
|
_logger.Warning("Could not find a layout provider for type {LayoutType} of device {Device}", device.LayoutSelection.Type, device);
|
||||||
device.ApplyLayout(layout, device.DeviceProvider.CreateMissingLedsSupported, device.DeviceProvider.RemoveExcessiveLedsSupported);
|
|
||||||
|
ArtemisLayout? layout = provider?.GetDeviceLayout(device);
|
||||||
|
if (layout != null && !layout.IsValid)
|
||||||
|
{
|
||||||
|
_logger.Warning("Got an invalid layout {Layout} from {LayoutProvider}", layout, provider!.GetType().FullName);
|
||||||
|
layout = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (layout == null)
|
||||||
|
device.ApplyLayout(null, false, false);
|
||||||
|
else
|
||||||
|
provider?.ApplyLayout(device, layout);
|
||||||
|
}
|
||||||
|
catch (Exception e)
|
||||||
|
{
|
||||||
|
_logger.Error(e, "Failed to apply device layout");
|
||||||
|
}
|
||||||
|
|
||||||
UpdateLeds();
|
UpdateLeds();
|
||||||
}
|
}
|
||||||
@ -230,7 +256,7 @@ internal class DeviceService : IDeviceService
|
|||||||
device = new ArtemisDevice(rgbDevice, deviceProvider);
|
device = new ArtemisDevice(rgbDevice, deviceProvider);
|
||||||
}
|
}
|
||||||
|
|
||||||
ApplyDeviceLayout(device, device.GetBestDeviceLayout());
|
LoadDeviceLayout(device);
|
||||||
return device;
|
return device;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -43,11 +43,10 @@ public interface IDeviceService : IArtemisService
|
|||||||
void AutoArrangeDevices();
|
void AutoArrangeDevices();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Apples the provided <see cref="ArtemisLayout" /> to the provided <see cref="ArtemisDevice" />
|
/// Apples the best available to the provided <see cref="ArtemisDevice" />
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="device"></param>
|
/// <param name="device"></param>
|
||||||
/// <param name="layout"></param>
|
void LoadDeviceLayout(ArtemisDevice device);
|
||||||
void ApplyDeviceLayout(ArtemisDevice device, ArtemisLayout? layout);
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Enables the provided device
|
/// Enables the provided device
|
||||||
|
|||||||
@ -31,7 +31,7 @@ internal class PluginManagementService : IPluginManagementService
|
|||||||
private readonly IPluginRepository _pluginRepository;
|
private readonly IPluginRepository _pluginRepository;
|
||||||
private readonly List<Plugin> _plugins;
|
private readonly List<Plugin> _plugins;
|
||||||
private readonly IQueuedActionRepository _queuedActionRepository;
|
private readonly IQueuedActionRepository _queuedActionRepository;
|
||||||
private FileSystemWatcher _hotReloadWatcher;
|
private FileSystemWatcher? _hotReloadWatcher;
|
||||||
private bool _disposed;
|
private bool _disposed;
|
||||||
private bool _isElevated;
|
private bool _isElevated;
|
||||||
|
|
||||||
@ -57,7 +57,7 @@ internal class PluginManagementService : IPluginManagementService
|
|||||||
|
|
||||||
// Remove the old directory if it exists
|
// Remove the old directory if it exists
|
||||||
if (Directory.Exists(pluginDirectory.FullName))
|
if (Directory.Exists(pluginDirectory.FullName))
|
||||||
pluginDirectory.DeleteRecursively();
|
pluginDirectory.Delete(true);
|
||||||
|
|
||||||
// Extract everything in the same archive directory to the unique plugin directory
|
// Extract everything in the same archive directory to the unique plugin directory
|
||||||
Utilities.CreateAccessibleDirectory(pluginDirectory.FullName);
|
Utilities.CreateAccessibleDirectory(pluginDirectory.FullName);
|
||||||
|
|||||||
@ -1,24 +1,49 @@
|
|||||||
namespace Artemis.Core.Services;
|
namespace Artemis.Core.Services;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// This readonly struct provides information about a process.
|
||||||
|
/// </summary>
|
||||||
public readonly struct ProcessInfo
|
public readonly struct ProcessInfo
|
||||||
{
|
{
|
||||||
#region Properties & Fields
|
#region Properties & Fields
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Identifier for the process.
|
||||||
|
/// </summary>
|
||||||
public readonly int ProcessId;
|
public readonly int ProcessId;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the name of the process.
|
||||||
|
/// </summary>
|
||||||
public readonly string ProcessName;
|
public readonly string ProcessName;
|
||||||
public readonly string ImageName; //TODO DarthAffe 01.09.2023: Do we need this if we can't get it through Process.GetProcesses()?
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Image Name of the Process.
|
||||||
|
/// </summary>
|
||||||
|
public readonly string ImageName; // TODO DarthAffe 01.09.2023: Do we need this if we can't get it through Process.GetProcesses()?
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the Executable associated with the Process.
|
||||||
|
/// </summary>
|
||||||
public readonly string Executable;
|
public readonly string Executable;
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Constructors
|
#region Constructors
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="ProcessInfo"/> struct.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="processId">The identifier for the process.</param>
|
||||||
|
/// <param name="processName">The name of the process.</param>
|
||||||
|
/// <param name="imageName">The Image Name of the process.</param>
|
||||||
|
/// <param name="executable">The executable associated with the process.</param>
|
||||||
public ProcessInfo(int processId, string processName, string imageName, string executable)
|
public ProcessInfo(int processId, string processName, string imageName, string executable)
|
||||||
{
|
{
|
||||||
this.ProcessId = processId;
|
ProcessId = processId;
|
||||||
this.ProcessName = processName;
|
ProcessName = processName;
|
||||||
this.ImageName = imageName;
|
ImageName = imageName;
|
||||||
this.Executable = executable;
|
Executable = executable;
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@ -75,8 +75,8 @@ internal class RenderService : IRenderService, IRenderer, IDisposable
|
|||||||
_frameStopWatch.Restart();
|
_frameStopWatch.Restart();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
OnFrameRendering(new FrameRenderingEventArgs(canvas, delta, _surfaceManager.Surface));
|
|
||||||
_coreRenderer.Render(canvas, delta);
|
_coreRenderer.Render(canvas, delta);
|
||||||
|
OnFrameRendering(new FrameRenderingEventArgs(canvas, delta, _surfaceManager.Surface));
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<Import Project="..\Artemis.props" />
|
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
<PreserveCompilationContext>false</PreserveCompilationContext>
|
<PreserveCompilationContext>false</PreserveCompilationContext>
|
||||||
@ -9,6 +7,6 @@
|
|||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="LiteDB" Version="5.0.17" />
|
<PackageReference Include="LiteDB" Version="5.0.17" />
|
||||||
<PackageReference Include="Serilog" Version="3.0.1" />
|
<PackageReference Include="Serilog" Version="3.1.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
@ -22,11 +22,11 @@ public class DeviceEntity
|
|||||||
public float GreenScale { get; set; }
|
public float GreenScale { get; set; }
|
||||||
public float BlueScale { get; set; }
|
public float BlueScale { get; set; }
|
||||||
public bool IsEnabled { get; set; }
|
public bool IsEnabled { get; set; }
|
||||||
|
|
||||||
public bool DisableDefaultLayout { get; set; }
|
|
||||||
public int PhysicalLayout { get; set; }
|
public int PhysicalLayout { get; set; }
|
||||||
public string LogicalLayout { get; set; }
|
public string LogicalLayout { get; set; }
|
||||||
public string CustomLayoutPath { get; set; }
|
public string LayoutType { get; set; }
|
||||||
|
public string LayoutParameter { get; set; }
|
||||||
|
|
||||||
public List<DeviceInputIdentifierEntity> InputIdentifiers { get; set; }
|
public List<DeviceInputIdentifierEntity> InputIdentifiers { get; set; }
|
||||||
public List<InputMappingEntity> InputMappings { get; set; }
|
public List<InputMappingEntity> InputMappings { get; set; }
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
namespace Artemis.Storage.Entities.Workshop;
|
namespace Artemis.Storage.Entities.Workshop;
|
||||||
|
|
||||||
@ -16,6 +17,6 @@ public class EntryEntity
|
|||||||
public long ReleaseId { get; set; }
|
public long ReleaseId { get; set; }
|
||||||
public string ReleaseVersion { get; set; }
|
public string ReleaseVersion { get; set; }
|
||||||
public DateTimeOffset InstalledAt { get; set; }
|
public DateTimeOffset InstalledAt { get; set; }
|
||||||
|
|
||||||
public string LocalReference { get; set; }
|
public Dictionary<string,object> Metadata { get; set; }
|
||||||
}
|
}
|
||||||
35
src/Artemis.Storage/Migrations/M0023LayoutProviders.cs
Normal file
35
src/Artemis.Storage/Migrations/M0023LayoutProviders.cs
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
using System.Collections.Generic;
|
||||||
|
using Artemis.Storage.Migrations.Interfaces;
|
||||||
|
using LiteDB;
|
||||||
|
|
||||||
|
namespace Artemis.Storage.Migrations;
|
||||||
|
|
||||||
|
public class M0023LayoutProviders : IStorageMigration
|
||||||
|
{
|
||||||
|
public int UserVersion => 23;
|
||||||
|
|
||||||
|
public void Apply(LiteRepository repository)
|
||||||
|
{
|
||||||
|
ILiteCollection<BsonDocument> deviceEntities = repository.Database.GetCollection("DeviceEntity");
|
||||||
|
List<BsonDocument> toUpdate = new();
|
||||||
|
|
||||||
|
foreach (BsonDocument bsonDocument in deviceEntities.FindAll())
|
||||||
|
{
|
||||||
|
if (bsonDocument.TryGetValue("CustomLayoutPath", out BsonValue customLayoutPath) && customLayoutPath.IsString && !string.IsNullOrEmpty(customLayoutPath.AsString))
|
||||||
|
{
|
||||||
|
bsonDocument.Add("LayoutType", new BsonValue("CustomPath"));
|
||||||
|
bsonDocument.Add("LayoutParameter", new BsonValue(customLayoutPath.AsString));
|
||||||
|
}
|
||||||
|
else if (bsonDocument.TryGetValue("DisableDefaultLayout", out BsonValue disableDefaultLayout) && disableDefaultLayout.AsBoolean)
|
||||||
|
bsonDocument.Add("LayoutType", new BsonValue("None"));
|
||||||
|
else
|
||||||
|
bsonDocument.Add("LayoutType", new BsonValue("Default"));
|
||||||
|
|
||||||
|
bsonDocument.Remove("CustomLayoutPath");
|
||||||
|
bsonDocument.Remove("DisableDefaultLayout");
|
||||||
|
toUpdate.Add(bsonDocument);
|
||||||
|
}
|
||||||
|
|
||||||
|
deviceEntities.Update(toUpdate);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,6 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<Import Project="..\Artemis.props" />
|
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
@ -17,14 +15,6 @@
|
|||||||
<AvaloniaResource Include="Assets\**" />
|
<AvaloniaResource Include="Assets\**" />
|
||||||
<None Remove=".gitignore" />
|
<None Remove=".gitignore" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Avalonia" Version="$(AvaloniaVersion)" />
|
|
||||||
<PackageReference Include="Avalonia.Desktop" Version="$(AvaloniaVersion)" />
|
|
||||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
|
||||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="$(AvaloniaVersion)" />
|
|
||||||
<PackageReference Include="Avalonia.ReactiveUI" Version="$(AvaloniaVersion)" />
|
|
||||||
<PackageReference Include="ReactiveUI" Version="19.4.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" />
|
<ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" />
|
||||||
<ProjectReference Include="..\Artemis.UI\Artemis.UI.csproj" />
|
<ProjectReference Include="..\Artemis.UI\Artemis.UI.csproj" />
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<Import Project="..\Artemis.props" />
|
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
@ -16,14 +14,6 @@
|
|||||||
<AvaloniaResource Include="Assets\**" />
|
<AvaloniaResource Include="Assets\**" />
|
||||||
<None Remove=".gitignore" />
|
<None Remove=".gitignore" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Avalonia" Version="$(AvaloniaVersion)" />
|
|
||||||
<PackageReference Include="Avalonia.Desktop" Version="$(AvaloniaVersion)" />
|
|
||||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
|
||||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="$(AvaloniaVersion)" />
|
|
||||||
<PackageReference Include="Avalonia.ReactiveUI" Version="$(AvaloniaVersion)" />
|
|
||||||
<PackageReference Include="ReactiveUI" Version="19.4.1" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" />
|
<ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" />
|
||||||
<ProjectReference Include="..\Artemis.UI\Artemis.UI.csproj" />
|
<ProjectReference Include="..\Artemis.UI\Artemis.UI.csproj" />
|
||||||
|
|||||||
@ -1,6 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<Import Project="..\Artemis.props" />
|
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
@ -12,19 +10,17 @@
|
|||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Avalonia" Version="$(AvaloniaVersion)" />
|
<PackageReference Include="Avalonia" Version="11.0.6" />
|
||||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
||||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="$(AvaloniaVersion)" />
|
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.0.6" />
|
||||||
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="$(AvaloniaVersion)" />
|
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.0.6" />
|
||||||
<PackageReference Include="Avalonia.ReactiveUI" Version="$(AvaloniaVersion)" />
|
<PackageReference Include="Avalonia.ReactiveUI" Version="11.0.6" />
|
||||||
<PackageReference Include="Avalonia.Xaml.Behaviors" Version="$(AvaloniaBehavioursVersion)" />
|
<PackageReference Include="Avalonia.Xaml.Behaviors" Version="11.0.6" />
|
||||||
<PackageReference Include="DynamicData" Version="7.14.2" />
|
<PackageReference Include="DynamicData" Version="8.3.27" />
|
||||||
<PackageReference Include="FluentAvaloniaUI" Version="$(FluentAvaloniaVersion)" />
|
<PackageReference Include="FluentAvaloniaUI" Version="2.0.5" />
|
||||||
<PackageReference Include="Material.Icons.Avalonia" Version="2.0.1" />
|
<PackageReference Include="Material.Icons.Avalonia" Version="2.1.0" />
|
||||||
<PackageReference Include="ReactiveUI" Version="19.4.1" />
|
<PackageReference Include="ReactiveUI" Version="19.5.39" />
|
||||||
<PackageReference Include="ReactiveUI.Validation" Version="3.1.7" />
|
<PackageReference Include="ReactiveUI.Validation" Version="3.1.7" />
|
||||||
<PackageReference Include="RGB.NET.Core" Version="$(RGBDotNetVersion)" />
|
|
||||||
<PackageReference Include="SkiaSharp" Version="$(SkiaSharpVersion)" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" />
|
<ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" />
|
||||||
|
|||||||
@ -15,7 +15,7 @@ public class LostFocusTextBoxBindingBehavior : Behavior<TextBox>
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the value of the binding.
|
/// Gets or sets the value of the binding.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static readonly StyledProperty<string> TextProperty = AvaloniaProperty.Register<LostFocusTextBoxBindingBehavior, string>(
|
public static readonly StyledProperty<string?> TextProperty = AvaloniaProperty.Register<LostFocusTextBoxBindingBehavior, string?>(
|
||||||
"Text", defaultBindingMode: BindingMode.TwoWay);
|
"Text", defaultBindingMode: BindingMode.TwoWay);
|
||||||
|
|
||||||
static LostFocusTextBoxBindingBehavior()
|
static LostFocusTextBoxBindingBehavior()
|
||||||
@ -26,7 +26,7 @@ public class LostFocusTextBoxBindingBehavior : Behavior<TextBox>
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets or sets the value of the binding.
|
/// Gets or sets the value of the binding.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public string Text
|
public string? Text
|
||||||
{
|
{
|
||||||
get => GetValue(TextProperty);
|
get => GetValue(TextProperty);
|
||||||
set => SetValue(TextProperty, value);
|
set => SetValue(TextProperty, value);
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
using Artemis.UI.Shared.Events;
|
using Artemis.UI.Shared.Events;
|
||||||
|
using Artemis.UI.Shared.Extensions;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Input;
|
using Avalonia.Input;
|
||||||
@ -36,7 +35,7 @@ public class DeviceVisualizer : Control
|
|||||||
private ArtemisDevice? _oldDevice;
|
private ArtemisDevice? _oldDevice;
|
||||||
private bool _loading;
|
private bool _loading;
|
||||||
private Color[] _previousState = Array.Empty<Color>();
|
private Color[] _previousState = Array.Empty<Color>();
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public DeviceVisualizer()
|
public DeviceVisualizer()
|
||||||
{
|
{
|
||||||
@ -69,11 +68,7 @@ public class DeviceVisualizer : Control
|
|||||||
|
|
||||||
// Render device and LED images
|
// Render device and LED images
|
||||||
if (_deviceImage != null)
|
if (_deviceImage != null)
|
||||||
drawingContext.DrawImage(
|
drawingContext.DrawImage(_deviceImage, new Rect(_deviceImage.Size), new Rect(0, 0, Device.RgbDevice.ActualSize.Width, Device.RgbDevice.ActualSize.Height));
|
||||||
_deviceImage,
|
|
||||||
new Rect(_deviceImage.Size),
|
|
||||||
new Rect(0, 0, Device.RgbDevice.ActualSize.Width, Device.RgbDevice.ActualSize.Height)
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!ShowColors)
|
if (!ShowColors)
|
||||||
return;
|
return;
|
||||||
@ -163,7 +158,7 @@ public class DeviceVisualizer : Control
|
|||||||
{
|
{
|
||||||
if (Device == null || float.IsNaN(Device.RgbDevice.ActualSize.Width) || float.IsNaN(Device.RgbDevice.ActualSize.Height))
|
if (Device == null || float.IsNaN(Device.RgbDevice.ActualSize.Width) || float.IsNaN(Device.RgbDevice.ActualSize.Height))
|
||||||
return new Rect();
|
return new Rect();
|
||||||
|
|
||||||
Rect deviceRect = new(0, 0, Device.RgbDevice.ActualSize.Width, Device.RgbDevice.ActualSize.Height);
|
Rect deviceRect = new(0, 0, Device.RgbDevice.ActualSize.Width, Device.RgbDevice.ActualSize.Height);
|
||||||
Geometry geometry = new RectangleGeometry(deviceRect);
|
Geometry geometry = new RectangleGeometry(deviceRect);
|
||||||
geometry.Transform = new RotateTransform(Device.Rotation);
|
geometry.Transform = new RotateTransform(Device.Rotation);
|
||||||
@ -305,7 +300,7 @@ public class DeviceVisualizer : Control
|
|||||||
{
|
{
|
||||||
_deviceImage = await Task.Run(() => GetDeviceImage(device));
|
_deviceImage = await Task.Run(() => GetDeviceImage(device));
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception)
|
||||||
{
|
{
|
||||||
// ignored
|
// ignored
|
||||||
}
|
}
|
||||||
@ -316,34 +311,15 @@ public class DeviceVisualizer : Control
|
|||||||
|
|
||||||
private RenderTargetBitmap? GetDeviceImage(ArtemisDevice device)
|
private RenderTargetBitmap? GetDeviceImage(ArtemisDevice device)
|
||||||
{
|
{
|
||||||
string? path = device.Layout?.Image?.LocalPath;
|
ArtemisLayout? layout = device.Layout;
|
||||||
if (path == null)
|
if (layout == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
if (BitmapCache.TryGetValue(path, out RenderTargetBitmap? existingBitmap))
|
if (BitmapCache.TryGetValue(layout.FilePath, out RenderTargetBitmap? existingBitmap))
|
||||||
return existingBitmap;
|
return existingBitmap;
|
||||||
if (!File.Exists(path))
|
|
||||||
{
|
RenderTargetBitmap renderTargetBitmap = layout.RenderLayout(false);
|
||||||
BitmapCache[path] = null;
|
BitmapCache[layout.FilePath] = renderTargetBitmap;
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a bitmap that'll be used to render the device and LED images just once
|
|
||||||
// Render 4 times the actual size of the device to make sure things look sharp when zoomed in
|
|
||||||
RenderTargetBitmap renderTargetBitmap = new(new PixelSize((int) device.RgbDevice.ActualSize.Width * 2, (int) device.RgbDevice.ActualSize.Height * 2));
|
|
||||||
|
|
||||||
using DrawingContext context = renderTargetBitmap.CreateDrawingContext();
|
|
||||||
using Bitmap bitmap = new(path);
|
|
||||||
using Bitmap scaledBitmap = bitmap.CreateScaledBitmap(renderTargetBitmap.PixelSize);
|
|
||||||
|
|
||||||
context.DrawImage(scaledBitmap, new Rect(scaledBitmap.Size));
|
|
||||||
lock (_deviceVisualizerLeds)
|
|
||||||
{
|
|
||||||
foreach (DeviceVisualizerLed deviceVisualizerLed in _deviceVisualizerLeds)
|
|
||||||
deviceVisualizerLed.DrawBitmap(context, 2 * device.Scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
// BitmapCache[path] = renderTargetBitmap;
|
|
||||||
return renderTargetBitmap;
|
return renderTargetBitmap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.IO;
|
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using Avalonia.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;
|
||||||
@ -30,27 +28,7 @@ internal class DeviceVisualizerLed
|
|||||||
|
|
||||||
public ArtemisLed Led { get; }
|
public ArtemisLed Led { get; }
|
||||||
public Geometry? DisplayGeometry { get; private set; }
|
public Geometry? DisplayGeometry { get; private set; }
|
||||||
|
|
||||||
public void DrawBitmap(DrawingContext drawingContext, double scale)
|
|
||||||
{
|
|
||||||
if (Led.Layout?.Image == null || !File.Exists(Led.Layout.Image.LocalPath))
|
|
||||||
return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
using Bitmap bitmap = new(Led.Layout.Image.LocalPath);
|
|
||||||
using Bitmap scaledBitmap = bitmap.CreateScaledBitmap(new PixelSize((Led.RgbLed.Size.Width * scale).RoundToInt(), (Led.RgbLed.Size.Height * scale).RoundToInt()));
|
|
||||||
drawingContext.DrawImage(
|
|
||||||
scaledBitmap,
|
|
||||||
new Rect(Led.RgbLed.Location.X * scale, Led.RgbLed.Location.Y * scale, scaledBitmap.Size.Width, scaledBitmap.Size.Height)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// ignored
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RenderGeometry(DrawingContext drawingContext)
|
public void RenderGeometry(DrawingContext drawingContext)
|
||||||
{
|
{
|
||||||
if (DisplayGeometry == null)
|
if (DisplayGeometry == null)
|
||||||
|
|||||||
@ -19,32 +19,32 @@ namespace Artemis.UI.Shared.Pagination;
|
|||||||
[TemplatePart("PART_PagesView", typeof(StackPanel))]
|
[TemplatePart("PART_PagesView", typeof(StackPanel))]
|
||||||
public partial class Pagination : TemplatedControl
|
public partial class Pagination : TemplatedControl
|
||||||
{
|
{
|
||||||
|
private Button? _previousButton;
|
||||||
|
private Button? _nextButton;
|
||||||
|
private StackPanel? _pagesView;
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public Pagination()
|
public Pagination()
|
||||||
{
|
{
|
||||||
PropertyChanged += OnPropertyChanged;
|
PropertyChanged += OnPropertyChanged;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Button? PreviousButton { get; set; }
|
|
||||||
public Button? NextButton { get; set; }
|
|
||||||
public StackPanel? PagesView { get; set; }
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||||
{
|
{
|
||||||
if (PreviousButton != null)
|
if (_previousButton != null)
|
||||||
PreviousButton.Click -= PreviousButtonOnClick;
|
_previousButton.Click -= PreviousButtonOnClick;
|
||||||
if (NextButton != null)
|
if (_nextButton != null)
|
||||||
NextButton.Click -= NextButtonOnClick;
|
_nextButton.Click -= NextButtonOnClick;
|
||||||
|
|
||||||
PreviousButton = e.NameScope.Find<Button>("PART_PreviousButton");
|
_previousButton = e.NameScope.Find<Button>("PART_PreviousButton");
|
||||||
NextButton = e.NameScope.Find<Button>("PART_NextButton");
|
_nextButton = e.NameScope.Find<Button>("PART_NextButton");
|
||||||
PagesView = e.NameScope.Find<StackPanel>("PART_PagesView");
|
_pagesView = e.NameScope.Find<StackPanel>("PART_PagesView");
|
||||||
|
|
||||||
if (PreviousButton != null)
|
if (_previousButton != null)
|
||||||
PreviousButton.Click += PreviousButtonOnClick;
|
_previousButton.Click += PreviousButtonOnClick;
|
||||||
if (NextButton != null)
|
if (_nextButton != null)
|
||||||
NextButton.Click += NextButtonOnClick;
|
_nextButton.Click += NextButtonOnClick;
|
||||||
|
|
||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
@ -69,40 +69,40 @@ public partial class Pagination : TemplatedControl
|
|||||||
|
|
||||||
private void Update()
|
private void Update()
|
||||||
{
|
{
|
||||||
if (PagesView == null)
|
if (_pagesView == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
List<int> pages = GetPages(Value, Maximum);
|
List<int> pages = GetPages(Value, Maximum);
|
||||||
|
|
||||||
// Remove extra children
|
// Remove extra children
|
||||||
while (PagesView.Children.Count > pages.Count)
|
while (_pagesView.Children.Count > pages.Count)
|
||||||
{
|
{
|
||||||
PagesView.Children.RemoveAt(PagesView.Children.Count - 1);
|
_pagesView.Children.RemoveAt(_pagesView.Children.Count - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PagesView.Children.Count > pages.Count)
|
if (_pagesView.Children.Count > pages.Count)
|
||||||
PagesView.Children.RemoveRange(0, PagesView.Children.Count - pages.Count);
|
_pagesView.Children.RemoveRange(0, _pagesView.Children.Count - pages.Count);
|
||||||
|
|
||||||
// Add/modify children
|
// Add/modify children
|
||||||
for (int i = 0; i < pages.Count; i++)
|
for (int i = 0; i < pages.Count; i++)
|
||||||
{
|
{
|
||||||
int page = pages[i];
|
int page = pages[i];
|
||||||
|
|
||||||
// -1 indicates an ellipsis (...)
|
// -1 indicates an ellipsis (...)
|
||||||
if (page == -1)
|
if (page == -1)
|
||||||
{
|
{
|
||||||
if (PagesView.Children.ElementAtOrDefault(i) is not PaginationEllipsis)
|
if (_pagesView.Children.ElementAtOrDefault(i) is not PaginationEllipsis)
|
||||||
{
|
{
|
||||||
if (PagesView.Children.Count - 1 >= i)
|
if (_pagesView.Children.Count - 1 >= i)
|
||||||
PagesView.Children[i] = new PaginationEllipsis();
|
_pagesView.Children[i] = new PaginationEllipsis();
|
||||||
else
|
else
|
||||||
PagesView.Children.Add(new PaginationEllipsis());
|
_pagesView.Children.Add(new PaginationEllipsis());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Anything else indicates a regular page
|
// Anything else indicates a regular page
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (PagesView.Children.ElementAtOrDefault(i) is PaginationPage paginationPage)
|
if (_pagesView.Children.ElementAtOrDefault(i) is PaginationPage paginationPage)
|
||||||
{
|
{
|
||||||
paginationPage.Page = page;
|
paginationPage.Page = page;
|
||||||
paginationPage.Command = ReactiveCommand.Create(() => Value = page);
|
paginationPage.Command = ReactiveCommand.Create(() => Value = page);
|
||||||
@ -110,14 +110,14 @@ public partial class Pagination : TemplatedControl
|
|||||||
}
|
}
|
||||||
|
|
||||||
paginationPage = new PaginationPage {Page = page, Command = ReactiveCommand.Create(() => Value = page)};
|
paginationPage = new PaginationPage {Page = page, Command = ReactiveCommand.Create(() => Value = page)};
|
||||||
if (PagesView.Children.Count - 1 >= i)
|
if (_pagesView.Children.Count - 1 >= i)
|
||||||
PagesView.Children[i] = paginationPage;
|
_pagesView.Children[i] = paginationPage;
|
||||||
else
|
else
|
||||||
PagesView.Children.Add(paginationPage);
|
_pagesView.Children.Add(paginationPage);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (Control child in PagesView.Children)
|
foreach (Control child in _pagesView.Children)
|
||||||
{
|
{
|
||||||
if (child is PaginationPage paginationPage)
|
if (child is PaginationPage paginationPage)
|
||||||
((IPseudoClasses) paginationPage.Classes).Set(":selected", paginationPage.Page == Value);
|
((IPseudoClasses) paginationPage.Classes).Set(":selected", paginationPage.Page == Value);
|
||||||
|
|||||||
@ -8,10 +8,17 @@ using ReactiveUI;
|
|||||||
|
|
||||||
namespace Artemis.UI.Shared.TagsInput;
|
namespace Artemis.UI.Shared.TagsInput;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents an input for tags.
|
||||||
|
/// </summary>
|
||||||
[TemplatePart("PART_TagInputBox", typeof(TextBox))]
|
[TemplatePart("PART_TagInputBox", typeof(TextBox))]
|
||||||
public partial class TagsInput : TemplatedControl
|
public partial class TagsInput : TemplatedControl
|
||||||
{
|
{
|
||||||
public TextBox? TagInputBox { get; set; }
|
private TextBox? _tagInputBox;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the command that is to be called when removing a tag
|
||||||
|
/// </summary>
|
||||||
public ICommand RemoveTag { get; }
|
public ICommand RemoveTag { get; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -23,18 +30,18 @@ public partial class TagsInput : TemplatedControl
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
|
||||||
{
|
{
|
||||||
if (TagInputBox != null)
|
if (_tagInputBox != null)
|
||||||
{
|
{
|
||||||
TagInputBox.KeyDown -= TagInputBoxOnKeyDown;
|
_tagInputBox.KeyDown -= TagInputBoxOnKeyDown;
|
||||||
TagInputBox.TextChanging -= TagInputBoxOnTextChanging;
|
_tagInputBox.TextChanging -= TagInputBoxOnTextChanging;
|
||||||
}
|
}
|
||||||
|
|
||||||
TagInputBox = e.NameScope.Find<TextBox>("PART_TagInputBox");
|
_tagInputBox = e.NameScope.Find<TextBox>("PART_TagInputBox");
|
||||||
|
|
||||||
if (TagInputBox != null)
|
if (_tagInputBox != null)
|
||||||
{
|
{
|
||||||
TagInputBox.KeyDown += TagInputBoxOnKeyDown;
|
_tagInputBox.KeyDown += TagInputBoxOnKeyDown;
|
||||||
TagInputBox.TextChanging += TagInputBoxOnTextChanging;
|
_tagInputBox.TextChanging += TagInputBoxOnTextChanging;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -42,21 +49,21 @@ public partial class TagsInput : TemplatedControl
|
|||||||
{
|
{
|
||||||
Tags.Remove(t);
|
Tags.Remove(t);
|
||||||
|
|
||||||
if (TagInputBox != null)
|
if (_tagInputBox != null)
|
||||||
TagInputBox.IsEnabled = Tags.Count < MaxLength;
|
_tagInputBox.IsEnabled = Tags.Count < MaxLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TagInputBoxOnTextChanging(object? sender, TextChangingEventArgs e)
|
private void TagInputBoxOnTextChanging(object? sender, TextChangingEventArgs e)
|
||||||
{
|
{
|
||||||
if (TagInputBox?.Text == null)
|
if (_tagInputBox?.Text == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TagInputBox.Text = CleanTagRegex().Replace(TagInputBox.Text.ToLower(), "");
|
_tagInputBox.Text = CleanTagRegex().Replace(_tagInputBox.Text.ToLower(), "");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void TagInputBoxOnKeyDown(object? sender, KeyEventArgs e)
|
private void TagInputBoxOnKeyDown(object? sender, KeyEventArgs e)
|
||||||
{
|
{
|
||||||
if (TagInputBox == null)
|
if (_tagInputBox == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (e.Key == Key.Space)
|
if (e.Key == Key.Space)
|
||||||
@ -64,13 +71,13 @@ public partial class TagsInput : TemplatedControl
|
|||||||
if (e.Key != Key.Enter)
|
if (e.Key != Key.Enter)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(TagInputBox.Text) || Tags.Contains(TagInputBox.Text) || Tags.Count >= MaxLength)
|
if (string.IsNullOrWhiteSpace(_tagInputBox.Text) || Tags.Contains(_tagInputBox.Text) || Tags.Count >= MaxLength)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Tags.Add(CleanTagRegex().Replace(TagInputBox.Text.ToLower(), ""));
|
Tags.Add(CleanTagRegex().Replace(_tagInputBox.Text.ToLower(), ""));
|
||||||
|
|
||||||
TagInputBox.Text = "";
|
_tagInputBox.Text = "";
|
||||||
TagInputBox.IsEnabled = Tags.Count < MaxLength;
|
_tagInputBox.IsEnabled = Tags.Count < MaxLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
[GeneratedRegex("[\\s\\-]+")]
|
[GeneratedRegex("[\\s\\-]+")]
|
||||||
|
|||||||
@ -2,6 +2,9 @@ using System;
|
|||||||
|
|
||||||
namespace Artemis.UI.Shared;
|
namespace Artemis.UI.Shared;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Represents errors that occur within the Artemis router.
|
||||||
|
/// </summary>
|
||||||
public class ArtemisRoutingException : Exception
|
public class ArtemisRoutingException : Exception
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
|
|||||||
139
src/Artemis.UI.Shared/Extensions/ArtemisLayoutExtensions.cs
Normal file
139
src/Artemis.UI.Shared/Extensions/ArtemisLayoutExtensions.cs
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Media;
|
||||||
|
using Avalonia.Media.Imaging;
|
||||||
|
using RGB.NET.Core;
|
||||||
|
using Color = Avalonia.Media.Color;
|
||||||
|
using SolidColorBrush = Avalonia.Media.SolidColorBrush;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Shared.Extensions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides extension methods for the <see cref="ArtemisLayout" /> type.
|
||||||
|
/// </summary>
|
||||||
|
public static class ArtemisLayoutExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Renders the layout to a bitmap.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="layout">The layout to render</param>
|
||||||
|
/// <returns>The resulting bitmap.</returns>
|
||||||
|
public static RenderTargetBitmap RenderLayout(this ArtemisLayout layout, bool previewLeds)
|
||||||
|
{
|
||||||
|
string? path = layout.Image?.LocalPath;
|
||||||
|
|
||||||
|
// Create a bitmap that'll be used to render the device and LED images just once
|
||||||
|
// Render 4 times the actual size of the device to make sure things look sharp when zoomed in
|
||||||
|
RenderTargetBitmap renderTargetBitmap = new(new PixelSize((int) layout.RgbLayout.Width * 2, (int) layout.RgbLayout.Height * 2));
|
||||||
|
|
||||||
|
using DrawingContext context = renderTargetBitmap.CreateDrawingContext();
|
||||||
|
|
||||||
|
// Draw device background
|
||||||
|
if (path != null && File.Exists(path))
|
||||||
|
{
|
||||||
|
using Bitmap bitmap = new(path);
|
||||||
|
using Bitmap scaledBitmap = bitmap.CreateScaledBitmap(renderTargetBitmap.PixelSize);
|
||||||
|
context.DrawImage(scaledBitmap, new Rect(scaledBitmap.Size));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Draw LED images
|
||||||
|
foreach (ArtemisLedLayout led in layout.Leds)
|
||||||
|
{
|
||||||
|
string? ledPath = led.Image?.LocalPath;
|
||||||
|
if (ledPath == null || !File.Exists(ledPath))
|
||||||
|
continue;
|
||||||
|
using Bitmap bitmap = new(ledPath);
|
||||||
|
using Bitmap scaledBitmap = bitmap.CreateScaledBitmap(new PixelSize((led.RgbLayout.Width * 2).RoundToInt(), (led.RgbLayout.Height * 2).RoundToInt()));
|
||||||
|
context.DrawImage(scaledBitmap, new Rect(led.RgbLayout.X * 2, led.RgbLayout.Y * 2, scaledBitmap.Size.Width, scaledBitmap.Size.Height));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!previewLeds)
|
||||||
|
return renderTargetBitmap;
|
||||||
|
|
||||||
|
// Draw LED geometry using a rainbow gradient
|
||||||
|
ColorGradient colors = ColorGradient.GetUnicornBarf();
|
||||||
|
colors.ToggleSeamless();
|
||||||
|
context.PushTransform(Matrix.CreateScale(2, 2));
|
||||||
|
foreach (ArtemisLedLayout led in layout.Leds)
|
||||||
|
{
|
||||||
|
Geometry? geometry = CreateLedGeometry(led);
|
||||||
|
if (geometry == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
Color color = colors.GetColor((led.RgbLayout.X + led.RgbLayout.Width / 2) / layout.RgbLayout.Width).ToColor();
|
||||||
|
SolidColorBrush fillBrush = new() {Color = color, Opacity = 0.4};
|
||||||
|
SolidColorBrush penBrush = new() {Color = color};
|
||||||
|
Pen pen = new(penBrush) {LineJoin = PenLineJoin.Round};
|
||||||
|
context.DrawGeometry(fillBrush, pen, geometry);
|
||||||
|
}
|
||||||
|
|
||||||
|
return renderTargetBitmap;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Geometry? CreateLedGeometry(ArtemisLedLayout led)
|
||||||
|
{
|
||||||
|
// The minimum required size for geometry to be created
|
||||||
|
if (led.RgbLayout.Width < 2 || led.RgbLayout.Height < 2)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
switch (led.RgbLayout.Shape)
|
||||||
|
{
|
||||||
|
case Shape.Custom:
|
||||||
|
if (led.DeviceLayout.RgbLayout.Type is RGBDeviceType.Keyboard or RGBDeviceType.Keypad)
|
||||||
|
return CreateCustomGeometry(led, 2.0);
|
||||||
|
return CreateCustomGeometry(led, 1.0);
|
||||||
|
case Shape.Rectangle:
|
||||||
|
if (led.DeviceLayout.RgbLayout.Type is RGBDeviceType.Keyboard or RGBDeviceType.Keypad)
|
||||||
|
return CreateKeyCapGeometry(led);
|
||||||
|
return CreateRectangleGeometry(led);
|
||||||
|
case Shape.Circle:
|
||||||
|
return CreateCircleGeometry(led);
|
||||||
|
default:
|
||||||
|
throw new ArgumentOutOfRangeException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RectangleGeometry CreateRectangleGeometry(ArtemisLedLayout led)
|
||||||
|
{
|
||||||
|
return new RectangleGeometry(new Rect(led.RgbLayout.X + 0.5, led.RgbLayout.Y + 0.5, led.RgbLayout.Width - 1, led.RgbLayout.Height - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static EllipseGeometry CreateCircleGeometry(ArtemisLedLayout led)
|
||||||
|
{
|
||||||
|
return new EllipseGeometry(new Rect(led.RgbLayout.X + 0.5, led.RgbLayout.Y + 0.5, led.RgbLayout.Width - 1, led.RgbLayout.Height - 1));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static RectangleGeometry CreateKeyCapGeometry(ArtemisLedLayout led)
|
||||||
|
{
|
||||||
|
return new RectangleGeometry(new Rect(led.RgbLayout.X + 1, led.RgbLayout.Y + 1, led.RgbLayout.Width - 2, led.RgbLayout.Height - 2));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Geometry? CreateCustomGeometry(ArtemisLedLayout led, double deflateAmount)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
if (led.RgbLayout.ShapeData == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
double width = led.RgbLayout.Width - deflateAmount;
|
||||||
|
double height = led.RgbLayout.Height - deflateAmount;
|
||||||
|
|
||||||
|
Geometry geometry = Geometry.Parse(led.RgbLayout.ShapeData);
|
||||||
|
geometry.Transform = new TransformGroup
|
||||||
|
{
|
||||||
|
Children = new Transforms
|
||||||
|
{
|
||||||
|
new ScaleTransform(width, height),
|
||||||
|
new TranslateTransform(led.RgbLayout.X + deflateAmount / 2, led.RgbLayout.Y + deflateAmount / 2)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
return geometry;
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
return CreateRectangleGeometry(led);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -5,50 +5,60 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.UI.Shared.Utilities;
|
using Artemis.UI.Shared.Utilities;
|
||||||
|
|
||||||
namespace Artemis.UI.Shared.Extensions
|
namespace Artemis.UI.Shared.Extensions;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides extension methods for the <see cref="HttpClient" /> type.
|
||||||
|
/// </summary>
|
||||||
|
public static class HttpClientProgressExtensions
|
||||||
{
|
{
|
||||||
public static class HttpClientProgressExtensions
|
/// <summary>
|
||||||
|
/// Send a GET request to the specified Uri with an HTTP completion option and a cancellation token as an asynchronous operation.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="client">The HTTP client to use.</param>
|
||||||
|
/// <param name="requestUrl">The Uri the request is sent to.</param>
|
||||||
|
/// <param name="destination">The destination stream.</param>
|
||||||
|
/// <param name="progress">The progress instance to use for progress indication.</param>
|
||||||
|
/// <param name="cancellationToken">A cancellation token that can be used by other objects or threads to receive notice of cancellation.</param>
|
||||||
|
public static async Task DownloadDataAsync(this HttpClient client, string requestUrl, Stream destination, IProgress<StreamProgress>? progress, CancellationToken cancellationToken)
|
||||||
{
|
{
|
||||||
public static async Task DownloadDataAsync(this HttpClient client, string requestUrl, Stream destination, IProgress<StreamProgress>? progress, CancellationToken cancellationToken)
|
using HttpResponseMessage response = await client.GetAsync(requestUrl, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
|
||||||
|
response.EnsureSuccessStatusCode();
|
||||||
|
|
||||||
|
long? contentLength = response.Content.Headers.ContentLength;
|
||||||
|
await using Stream download = await response.Content.ReadAsStreamAsync(cancellationToken);
|
||||||
|
// no progress... no contentLength... very sad
|
||||||
|
if (progress is null || !contentLength.HasValue)
|
||||||
{
|
{
|
||||||
using HttpResponseMessage response = await client.GetAsync(requestUrl, HttpCompletionOption.ResponseHeadersRead, cancellationToken);
|
await download.CopyToAsync(destination, cancellationToken);
|
||||||
response.EnsureSuccessStatusCode();
|
return;
|
||||||
|
|
||||||
long? contentLength = response.Content.Headers.ContentLength;
|
|
||||||
await using Stream download = await response.Content.ReadAsStreamAsync(cancellationToken);
|
|
||||||
// no progress... no contentLength... very sad
|
|
||||||
if (progress is null || !contentLength.HasValue)
|
|
||||||
{
|
|
||||||
await download.CopyToAsync(destination, cancellationToken);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Such progress and contentLength much reporting Wow!
|
|
||||||
await download.CopyToAsync(destination, 81920, progress, contentLength, cancellationToken);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static async Task CopyToAsync(this Stream source, Stream destination, int bufferSize, IProgress<StreamProgress> progress, long? contentLength, CancellationToken cancellationToken)
|
// Such progress and contentLength much reporting Wow!
|
||||||
{
|
await download.CopyToAsync(destination, 81920, progress, contentLength, cancellationToken);
|
||||||
if (bufferSize < 0)
|
}
|
||||||
throw new ArgumentOutOfRangeException(nameof(bufferSize));
|
|
||||||
if (source is null)
|
|
||||||
throw new ArgumentNullException(nameof(source));
|
|
||||||
if (!source.CanRead)
|
|
||||||
throw new InvalidOperationException($"'{nameof(source)}' is not readable.");
|
|
||||||
if (destination == null)
|
|
||||||
throw new ArgumentNullException(nameof(destination));
|
|
||||||
if (!destination.CanWrite)
|
|
||||||
throw new InvalidOperationException($"'{nameof(destination)}' is not writable.");
|
|
||||||
|
|
||||||
byte[] buffer = new byte[bufferSize];
|
private static async Task CopyToAsync(this Stream source, Stream destination, int bufferSize, IProgress<StreamProgress> progress, long? contentLength, CancellationToken cancellationToken)
|
||||||
long totalBytesRead = 0;
|
{
|
||||||
int bytesRead;
|
if (bufferSize < 0)
|
||||||
while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0)
|
throw new ArgumentOutOfRangeException(nameof(bufferSize));
|
||||||
{
|
if (source is null)
|
||||||
await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
|
throw new ArgumentNullException(nameof(source));
|
||||||
totalBytesRead += bytesRead;
|
if (!source.CanRead)
|
||||||
progress?.Report(new StreamProgress(totalBytesRead, contentLength ?? totalBytesRead));
|
throw new InvalidOperationException($"'{nameof(source)}' is not readable.");
|
||||||
}
|
if (destination == null)
|
||||||
|
throw new ArgumentNullException(nameof(destination));
|
||||||
|
if (!destination.CanWrite)
|
||||||
|
throw new InvalidOperationException($"'{nameof(destination)}' is not writable.");
|
||||||
|
|
||||||
|
byte[] buffer = new byte[bufferSize];
|
||||||
|
long totalBytesRead = 0;
|
||||||
|
int bytesRead;
|
||||||
|
while ((bytesRead = await source.ReadAsync(buffer, 0, buffer.Length, cancellationToken).ConfigureAwait(false)) != 0)
|
||||||
|
{
|
||||||
|
await destination.WriteAsync(buffer, 0, bytesRead, cancellationToken).ConfigureAwait(false);
|
||||||
|
totalBytesRead += bytesRead;
|
||||||
|
progress?.Report(new StreamProgress(totalBytesRead, contentLength ?? totalBytesRead));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -107,7 +107,7 @@ public class ContentDialogBuilder
|
|||||||
_contentDialog.IsSecondaryButtonEnabled = builder.Command.CanExecute(builder.CommandParameter);
|
_contentDialog.IsSecondaryButtonEnabled = builder.Command.CanExecute(builder.CommandParameter);
|
||||||
builder.Command.CanExecuteChanged += (_, _) => _contentDialog.IsSecondaryButtonEnabled = builder.Command.CanExecute(builder.CommandParameter);
|
builder.Command.CanExecuteChanged += (_, _) => _contentDialog.IsSecondaryButtonEnabled = builder.Command.CanExecute(builder.CommandParameter);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -148,6 +148,16 @@ public class ContentDialogBuilder
|
|||||||
_contentDialog.FullSizeDesired = true;
|
_contentDialog.FullSizeDesired = true;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Changes the dialog to be full screen.
|
||||||
|
/// </summary>
|
||||||
|
/// <returns>The builder that can be used to further build the dialog.</returns>
|
||||||
|
public ContentDialogBuilder WithFullScreen()
|
||||||
|
{
|
||||||
|
_contentDialog.Classes.Add("fullscreen");
|
||||||
|
return this;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Asynchronously shows the content dialog.
|
/// Asynchronously shows the content dialog.
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Platform.Storage;
|
using Avalonia.Platform.Storage;
|
||||||
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace Artemis.UI.Shared.Services.Builders;
|
namespace Artemis.UI.Shared.Services.Builders;
|
||||||
|
|
||||||
@ -37,6 +38,29 @@ public class FileDialogFilterBuilder
|
|||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds all supported bitmap types to the filter.
|
||||||
|
/// </summary>
|
||||||
|
public FileDialogFilterBuilder WithBitmaps()
|
||||||
|
{
|
||||||
|
// Formats from SKEncodedImageFormat
|
||||||
|
return WithExtension("astc")
|
||||||
|
.WithExtension("avif")
|
||||||
|
.WithExtension("bmp")
|
||||||
|
.WithExtension("dng")
|
||||||
|
.WithExtension("gif")
|
||||||
|
.WithExtension("heif")
|
||||||
|
.WithExtension("ico")
|
||||||
|
.WithExtension("jpg")
|
||||||
|
.WithExtension("jpeg")
|
||||||
|
.WithExtension("ktx")
|
||||||
|
.WithExtension("pkm")
|
||||||
|
.WithExtension("png")
|
||||||
|
.WithExtension("wbmp")
|
||||||
|
.WithExtension("webp")
|
||||||
|
.WithName("Bitmap image");
|
||||||
|
}
|
||||||
|
|
||||||
internal FilePickerFileType Build()
|
internal FilePickerFileType Build()
|
||||||
{
|
{
|
||||||
return new FilePickerFileType(_name)
|
return new FilePickerFileType(_name)
|
||||||
|
|||||||
@ -61,7 +61,10 @@ internal class WindowService : IWindowService
|
|||||||
public async Task ShowDialogAsync(object viewModel)
|
public async Task ShowDialogAsync(object viewModel)
|
||||||
{
|
{
|
||||||
Window? parent = GetCurrentWindow();
|
Window? parent = GetCurrentWindow();
|
||||||
|
|
||||||
|
if (parent == null)
|
||||||
|
throw new ArtemisSharedUIException("Failed to get the current window.");
|
||||||
|
|
||||||
string name = viewModel.GetType().FullName!.Split('`')[0].Replace("ViewModel", "View");
|
string name = viewModel.GetType().FullName!.Split('`')[0].Replace("ViewModel", "View");
|
||||||
Type? type = viewModel.GetType().Assembly.GetType(name);
|
Type? type = viewModel.GetType().Assembly.GetType(name);
|
||||||
|
|
||||||
@ -100,6 +103,9 @@ internal class WindowService : IWindowService
|
|||||||
public async Task<TResult> ShowDialogAsync<TResult>(DialogViewModelBase<TResult> viewModel)
|
public async Task<TResult> ShowDialogAsync<TResult>(DialogViewModelBase<TResult> viewModel)
|
||||||
{
|
{
|
||||||
Window? parent = GetCurrentWindow();
|
Window? parent = GetCurrentWindow();
|
||||||
|
|
||||||
|
if (parent == null)
|
||||||
|
throw new ArtemisSharedUIException("Failed to get the current window.");
|
||||||
|
|
||||||
string name = viewModel.GetType().FullName!.Split('`')[0].Replace("ViewModel", "View");
|
string name = viewModel.GetType().FullName!.Split('`')[0].Replace("ViewModel", "View");
|
||||||
Type? type = viewModel.GetType().Assembly.GetType(name);
|
Type? type = viewModel.GetType().Assembly.GetType(name);
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
<StackPanel>
|
<StackPanel>
|
||||||
<Border Classes="card" Margin="20">
|
<Border Classes="card" Margin="20">
|
||||||
<TextBlock>I'm in a panel yo!</TextBlock>
|
<TextBlock>I'm in a panel yo!</TextBlock>
|
||||||
</Border>
|
</Border>
|
||||||
<Border Classes="card" Margin="20">
|
<Border Classes="card" Margin="20">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBlock>I'm in a panel yo!</TextBlock>
|
<TextBlock>I'm in a panel yo!</TextBlock>
|
||||||
|
|||||||
@ -27,22 +27,7 @@
|
|||||||
<Setter Property="Maximum" Value="{x:Static system:Double.MaxValue}"></Setter>
|
<Setter Property="Maximum" Value="{x:Static system:Double.MaxValue}"></Setter>
|
||||||
<Setter Property="Minimum" Value="{x:Static system:Double.MinValue}"></Setter>
|
<Setter Property="Minimum" Value="{x:Static system:Double.MinValue}"></Setter>
|
||||||
</Style>
|
</Style>
|
||||||
<Style Selector="controls|NumberBox /template/ TextBox.NumberBoxTextBoxStyle /template/ TextBlock#PART_Prefix">
|
<Style Selector="controls|NumberBox /template/ TextBox#InputBox">
|
||||||
<Setter Property="Foreground" Value="{DynamicResource TextControlForegroundDisabled}"></Setter>
|
|
||||||
<Setter Property="Margin" Value="-4 0 -12 0"></Setter>
|
|
||||||
</Style>
|
|
||||||
<Style Selector="controls|NumberBox /template/ TextBox.NumberBoxTextBoxStyle /template/ TextBlock#PART_Suffix">
|
|
||||||
<Setter Property="Foreground" Value="{DynamicResource TextControlForegroundDisabled}"></Setter>
|
|
||||||
<Setter Property="Margin" Value="-12 0 0 0"></Setter>
|
|
||||||
</Style>
|
|
||||||
|
|
||||||
<Style Selector="controls|NumberBox.condensed /template/ TextBox.NumberBoxTextBoxStyle /template/ TextBlock#PART_Prefix">
|
|
||||||
<Setter Property="Margin" Value="0 0 -4 0"></Setter>
|
|
||||||
</Style>
|
|
||||||
<Style Selector="controls|NumberBox.condensed /template/ TextBox.NumberBoxTextBoxStyle /template/ TextBlock#PART_Suffix">
|
|
||||||
<Setter Property="Margin" Value="-4 0 0 0"></Setter>
|
|
||||||
</Style>
|
|
||||||
<Style Selector="controls|NumberBox /template/ TextBox.NumberBoxTextBoxStyle">
|
|
||||||
<Setter Property="attachedProperties:TextBoxAssist.PrefixText" Value="{TemplateBinding attachedProperties:NumberBoxAssist.PrefixText}"></Setter>
|
<Setter Property="attachedProperties:TextBoxAssist.PrefixText" Value="{TemplateBinding attachedProperties:NumberBoxAssist.PrefixText}"></Setter>
|
||||||
<Setter Property="attachedProperties:TextBoxAssist.SuffixText" Value="{TemplateBinding attachedProperties:NumberBoxAssist.SuffixText}"></Setter>
|
<Setter Property="attachedProperties:TextBoxAssist.SuffixText" Value="{TemplateBinding attachedProperties:NumberBoxAssist.SuffixText}"></Setter>
|
||||||
</Style>
|
</Style>
|
||||||
|
|||||||
@ -5,7 +5,21 @@
|
|||||||
<Design.PreviewWith>
|
<Design.PreviewWith>
|
||||||
<Border Padding="20">
|
<Border Padding="20">
|
||||||
<StackPanel Spacing="20">
|
<StackPanel Spacing="20">
|
||||||
|
<TextBox Width="200" Height="150" AcceptsReturn="True" xml:space="preserve">asdasdas asd
|
||||||
|
asdasd
|
||||||
|
asd
|
||||||
|
asd
|
||||||
|
asd
|
||||||
|
as
|
||||||
|
fdsfsdf
|
||||||
|
sdg
|
||||||
|
sdg
|
||||||
|
sdg
|
||||||
|
</TextBox>
|
||||||
|
<TextBox Width="200" Height="150" AcceptsReturn="True" xml:space="preserve">asdasdas asd
|
||||||
|
asdasd
|
||||||
|
asd
|
||||||
|
as</TextBox>
|
||||||
|
|
||||||
<!-- Add Controls for Previewer Here -->
|
<!-- Add Controls for Previewer Here -->
|
||||||
<TextBox Text="99999999"
|
<TextBox Text="99999999"
|
||||||
@ -46,12 +60,10 @@
|
|||||||
|
|
||||||
<Border Margin="{TemplateBinding BorderThickness}">
|
<Border Margin="{TemplateBinding BorderThickness}">
|
||||||
<Grid ColumnDefinitions="Auto,*,Auto">
|
<Grid ColumnDefinitions="Auto,*,Auto">
|
||||||
<ContentPresenter Grid.Column="0"
|
<ContentPresenter Grid.Column="0" Content="{TemplateBinding InnerLeftContent}" />
|
||||||
Grid.ColumnSpan="1"
|
|
||||||
Content="{TemplateBinding InnerLeftContent}" />
|
|
||||||
<Grid x:Name="PART_InnerGrid"
|
<Grid x:Name="PART_InnerGrid"
|
||||||
Grid.Column="1"
|
Grid.Column="1"
|
||||||
RowDefinitions="Auto,Auto"
|
RowDefinitions="Auto,*"
|
||||||
ColumnDefinitions="Auto,*,Auto"
|
ColumnDefinitions="Auto,*,Auto"
|
||||||
Cursor="IBeam"
|
Cursor="IBeam"
|
||||||
Margin="{TemplateBinding Padding}">
|
Margin="{TemplateBinding Padding}">
|
||||||
|
|||||||
@ -18,6 +18,9 @@ public static class UI
|
|||||||
{
|
{
|
||||||
private static readonly BehaviorSubject<bool> MicaEnabledSubject = new(false);
|
private static readonly BehaviorSubject<bool> MicaEnabledSubject = new(false);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the background event loop scheduler.
|
||||||
|
/// </summary>
|
||||||
public static EventLoopScheduler BackgroundScheduler = new(ts => new Thread(ts));
|
public static EventLoopScheduler BackgroundScheduler = new(ts => new Thread(ts));
|
||||||
|
|
||||||
static UI()
|
static UI()
|
||||||
|
|||||||
@ -1,119 +0,0 @@
|
|||||||
// Heavily based on:
|
|
||||||
// SkyClip
|
|
||||||
// - ProgressableStreamContent.cs
|
|
||||||
// --------------------------------------------------------------------
|
|
||||||
// Author: Jeff Hansen <jeff@jeffijoe.com>
|
|
||||||
// Copyright (C) Jeff Hansen 2015. All rights reserved.
|
|
||||||
|
|
||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
using System.Net;
|
|
||||||
using System.Net.Http;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Shared.Utilities;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Provides HTTP content based on a stream with support for IProgress.
|
|
||||||
/// </summary>
|
|
||||||
public class ProgressableStreamContent : StreamContent
|
|
||||||
{
|
|
||||||
private const int DEFAULT_BUFFER_SIZE = 4096;
|
|
||||||
|
|
||||||
private readonly int _bufferSize;
|
|
||||||
private readonly IProgress<StreamProgress> _progress;
|
|
||||||
private readonly Stream _streamToWrite;
|
|
||||||
private bool _contentConsumed;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="ProgressableStreamContent" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="streamToWrite">The stream to write.</param>
|
|
||||||
/// <param name="progress">The downloader.</param>
|
|
||||||
public ProgressableStreamContent(Stream streamToWrite, IProgress<StreamProgress> progress) : this(streamToWrite, DEFAULT_BUFFER_SIZE, progress)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Initializes a new instance of the <see cref="ProgressableStreamContent" /> class.
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="streamToWrite">The stream to write.</param>
|
|
||||||
/// <param name="bufferSize">The buffer size.</param>
|
|
||||||
/// <param name="progress">The downloader.</param>
|
|
||||||
public ProgressableStreamContent(Stream streamToWrite, int bufferSize, IProgress<StreamProgress> progress) : base(streamToWrite, bufferSize)
|
|
||||||
{
|
|
||||||
if (bufferSize <= 0)
|
|
||||||
throw new ArgumentOutOfRangeException(nameof(bufferSize));
|
|
||||||
|
|
||||||
_streamToWrite = streamToWrite;
|
|
||||||
_bufferSize = bufferSize;
|
|
||||||
_progress = progress;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override void Dispose(bool disposing)
|
|
||||||
{
|
|
||||||
if (disposing)
|
|
||||||
_streamToWrite.Dispose();
|
|
||||||
|
|
||||||
base.Dispose(disposing);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override async Task SerializeToStreamAsync(Stream stream, TransportContext? context)
|
|
||||||
{
|
|
||||||
await SerializeToStreamAsync(stream, context, CancellationToken.None);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override async Task SerializeToStreamAsync(Stream stream, TransportContext? context, CancellationToken cancellationToken)
|
|
||||||
{
|
|
||||||
PrepareContent();
|
|
||||||
|
|
||||||
byte[] buffer = new byte[_bufferSize];
|
|
||||||
long size = _streamToWrite.Length;
|
|
||||||
int uploaded = 0;
|
|
||||||
|
|
||||||
await using (_streamToWrite)
|
|
||||||
{
|
|
||||||
while (!cancellationToken.IsCancellationRequested)
|
|
||||||
{
|
|
||||||
int length = await _streamToWrite.ReadAsync(buffer, cancellationToken);
|
|
||||||
if (length <= 0)
|
|
||||||
break;
|
|
||||||
|
|
||||||
uploaded += length;
|
|
||||||
_progress.Report(new StreamProgress(uploaded, size));
|
|
||||||
await stream.WriteAsync(buffer, 0, length, cancellationToken);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <inheritdoc />
|
|
||||||
protected override bool TryComputeLength(out long length)
|
|
||||||
{
|
|
||||||
length = _streamToWrite.Length;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Prepares the content.
|
|
||||||
/// </summary>
|
|
||||||
/// <exception cref="System.InvalidOperationException">The stream has already been read.</exception>
|
|
||||||
private void PrepareContent()
|
|
||||||
{
|
|
||||||
if (_contentConsumed)
|
|
||||||
{
|
|
||||||
// If the content needs to be written to a target stream a 2nd time, then the stream must support
|
|
||||||
// seeking (e.g. a FileStream), otherwise the stream can't be copied a second time to a target
|
|
||||||
// stream (e.g. a NetworkStream).
|
|
||||||
if (_streamToWrite.CanSeek)
|
|
||||||
_streamToWrite.Position = 0;
|
|
||||||
else
|
|
||||||
throw new InvalidOperationException("The stream has already been read.");
|
|
||||||
}
|
|
||||||
|
|
||||||
_contentConsumed = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.ComponentModel;
|
||||||
using System.Runtime.CompilerServices;
|
using System.Runtime.CompilerServices;
|
||||||
using Artemis.UI.Shared.Events;
|
using Artemis.UI.Shared.Events;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
@ -100,6 +101,24 @@ public abstract class ValidatableViewModelBase : ReactiveValidationObject, IActi
|
|||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public ViewModelActivator Activator { get; } = new();
|
public ViewModelActivator Activator { get; } = new();
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raises the property changed event for the provided property.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="args">The event arguments containing the name of the property that changed.</param>
|
||||||
|
protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
|
||||||
|
{
|
||||||
|
this.RaisePropertyChanged(args.PropertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raises the property changing event for the provided property.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="args">The event arguments containing the name of the property that is changing.</param>
|
||||||
|
protected virtual void OnPropertyChanging(PropertyChangingEventArgs args)
|
||||||
|
{
|
||||||
|
this.RaisePropertyChanging(args.PropertyName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -153,4 +172,22 @@ public abstract class ViewModelBase : ReactiveObject
|
|||||||
this.RaisePropertyChanged(propertyName);
|
this.RaisePropertyChanged(propertyName);
|
||||||
return newValue;
|
return newValue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raises the property changed event for the provided property.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="args">The event arguments containing the name of the property that changed.</param>
|
||||||
|
protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
|
||||||
|
{
|
||||||
|
this.RaisePropertyChanged(args.PropertyName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Raises the property changing event for the provided property.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="args">The event arguments containing the name of the property that is changing.</param>
|
||||||
|
protected virtual void OnPropertyChanging(PropertyChangingEventArgs args)
|
||||||
|
{
|
||||||
|
this.RaisePropertyChanging(args.PropertyName);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<Import Project="..\Artemis.props" />
|
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>net7.0-windows10.0.17763.0</TargetFramework>
|
<TargetFramework>net7.0-windows10.0.17763.0</TargetFramework>
|
||||||
@ -23,18 +21,13 @@
|
|||||||
</None>
|
</None>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Avalonia" Version="$(AvaloniaVersion)" />
|
<PackageReference Include="Avalonia.Win32" Version="11.0.6" />
|
||||||
<PackageReference Include="Avalonia.Desktop" Version="$(AvaloniaVersion)" />
|
|
||||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
|
||||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="$(AvaloniaVersion)" />
|
|
||||||
<PackageReference Include="Avalonia.ReactiveUI" Version="$(AvaloniaVersion)" />
|
|
||||||
<PackageReference Include="Avalonia.Win32" Version="$(AvaloniaVersion)" />
|
|
||||||
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.3" />
|
<PackageReference Include="Microsoft.Toolkit.Uwp.Notifications" Version="7.1.3" />
|
||||||
<PackageReference Include="Microsoft.Win32" Version="2.0.1" />
|
<PackageReference Include="Microsoft.Win32" Version="2.0.1" />
|
||||||
|
<!-- Note: Do NOT upgrade this compatibility package to 8.X before updating to net8, it WILL break -->
|
||||||
<PackageReference Include="Microsoft.Windows.Compatibility" Version="7.0.5" />
|
<PackageReference Include="Microsoft.Windows.Compatibility" Version="7.0.5" />
|
||||||
<PackageReference Include="RawInput.Sharp" Version="0.1.1" />
|
<PackageReference Include="RawInput.Sharp" Version="0.1.3" />
|
||||||
<PackageReference Include="ReactiveUI" Version="19.4.1" />
|
<PackageReference Include="SkiaSharp.Vulkan.SharpVk" Version="2.88.7" />
|
||||||
<PackageReference Include="SkiaSharp.Vulkan.SharpVk" Version="$(SkiaSharpVersion)" />
|
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" />
|
<ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" />
|
||||||
|
|||||||
@ -9,17 +9,19 @@ namespace Artemis.UI.Windows.Providers;
|
|||||||
public class ProtocolProvider : IProtocolProvider
|
public class ProtocolProvider : IProtocolProvider
|
||||||
{
|
{
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task AssociateWithProtocol(string protocol)
|
public Task AssociateWithProtocol(string protocol)
|
||||||
{
|
{
|
||||||
string key = $"HKEY_CURRENT_USER\\Software\\Classes\\{protocol}";
|
string key = $"HKEY_CURRENT_USER\\Software\\Classes\\{protocol}";
|
||||||
Registry.SetValue($"{key}", null, "URL:artemis protocol");
|
Registry.SetValue($"{key}", null, "URL:artemis protocol");
|
||||||
Registry.SetValue($"{key}", "URL Protocol", "");
|
Registry.SetValue($"{key}", "URL Protocol", "");
|
||||||
Registry.SetValue($"{key}\\DefaultIcon", null, $"\"{Constants.ExecutablePath}\",1");
|
Registry.SetValue($"{key}\\DefaultIcon", null, $"\"{Constants.ExecutablePath}\",1");
|
||||||
Registry.SetValue($"{key}\\shell\\open\\command", null, $"\"{Constants.ExecutablePath}\", \"--route=%1\"");
|
Registry.SetValue($"{key}\\shell\\open\\command", null, $"\"{Constants.ExecutablePath}\", \"--route=%1\"");
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public async Task DisassociateWithProtocol(string protocol)
|
public Task DisassociateWithProtocol(string protocol)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
@ -30,5 +32,7 @@ public class ProtocolProvider : IProtocolProvider
|
|||||||
{
|
{
|
||||||
// Ignore errors (which means that the protocol wasn't associated before)
|
// Ignore errors (which means that the protocol wasn't associated before)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return Task.CompletedTask;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,6 +1,4 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
<Import Project="..\Artemis.props" />
|
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<OutputType>Library</OutputType>
|
<OutputType>Library</OutputType>
|
||||||
<TargetFramework>net7.0</TargetFramework>
|
<TargetFramework>net7.0</TargetFramework>
|
||||||
@ -18,31 +16,19 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="AsyncImageLoader.Avalonia" Version="3.2.0" />
|
<PackageReference Include="AsyncImageLoader.Avalonia" Version="3.2.1" />
|
||||||
<PackageReference Include="Avalonia" Version="$(AvaloniaVersion)" />
|
<PackageReference Include="Avalonia.AvaloniaEdit" Version="11.0.6" />
|
||||||
<PackageReference Include="Avalonia.AvaloniaEdit" Version="11.0.1" />
|
<PackageReference Include="Avalonia.Controls.PanAndZoom" Version="11.0.0.2" />
|
||||||
<PackageReference Include="Avalonia.Controls.PanAndZoom" Version="11.0.0" />
|
<PackageReference Include="Avalonia.Desktop" Version="11.0.6" />
|
||||||
<PackageReference Include="Avalonia.Desktop" Version="$(AvaloniaVersion)" />
|
|
||||||
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
|
|
||||||
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="$(AvaloniaVersion)" />
|
|
||||||
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="$(AvaloniaVersion)" />
|
|
||||||
<PackageReference Include="Avalonia.ReactiveUI" Version="$(AvaloniaVersion)" />
|
|
||||||
<PackageReference Include="Avalonia.Xaml.Behaviors" Version="$(AvaloniaBehavioursVersion)" />
|
|
||||||
<PackageReference Include="Avalonia.Skia.Lottie" Version="11.0.0" />
|
<PackageReference Include="Avalonia.Skia.Lottie" Version="11.0.0" />
|
||||||
<PackageReference Include="AvaloniaEdit.TextMate" Version="11.0.1" />
|
<PackageReference Include="AvaloniaEdit.TextMate" Version="11.0.6" />
|
||||||
<PackageReference Include="DryIoc.dll" Version="5.4.1" />
|
|
||||||
<PackageReference Include="DynamicData" Version="7.14.2" />
|
|
||||||
<PackageReference Include="FluentAvaloniaUI" Version="$(FluentAvaloniaVersion)" />
|
|
||||||
<PackageReference Include="Flurl.Http" Version="3.2.4" />
|
|
||||||
<PackageReference Include="Markdown.Avalonia.Tight" Version="11.0.2" />
|
<PackageReference Include="Markdown.Avalonia.Tight" Version="11.0.2" />
|
||||||
<PackageReference Include="Material.Icons.Avalonia" Version="2.0.1" />
|
<PackageReference Include="Octopus.Octodiff" Version="2.0.544" />
|
||||||
<PackageReference Include="Octopus.Octodiff" Version="2.0.326" />
|
<PackageReference Include="PropertyChanged.SourceGenerator" Version="1.1.0">
|
||||||
<PackageReference Include="ReactiveUI" Version="19.4.1" />
|
<PrivateAssets>all</PrivateAssets>
|
||||||
<PackageReference Include="ReactiveUI.Validation" Version="3.1.7" />
|
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||||
<PackageReference Include="RGB.NET.Core" Version="$(RGBDotNetVersion)" />
|
</PackageReference>
|
||||||
<PackageReference Include="RGB.NET.Layout" Version="$(RGBDotNetVersion)" />
|
<PackageReference Include="Splat.DryIoc" Version="14.8.12" />
|
||||||
<PackageReference Include="SkiaSharp" Version="$(SkiaSharpVersion)" />
|
|
||||||
<PackageReference Include="Splat.DryIoc" Version="14.7.1" />
|
|
||||||
<PackageReference Include="TextMateSharp.Grammars" Version="1.0.56" />
|
<PackageReference Include="TextMateSharp.Grammars" Version="1.0.56" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
|||||||
@ -33,9 +33,9 @@ public static class ArtemisBootstrapper
|
|||||||
{
|
{
|
||||||
if (_application != null || _container != null)
|
if (_application != null || _container != null)
|
||||||
throw new ArtemisUIException("UI already bootstrapped");
|
throw new ArtemisUIException("UI already bootstrapped");
|
||||||
|
|
||||||
Utilities.PrepareFirstLaunch();
|
Utilities.PrepareFirstLaunch();
|
||||||
|
|
||||||
application.RequestedThemeVariant = ThemeVariant.Dark;
|
application.RequestedThemeVariant = ThemeVariant.Dark;
|
||||||
_application = application;
|
_application = application;
|
||||||
_container = new Container(rules => rules
|
_container = new Container(rules => rules
|
||||||
@ -52,7 +52,7 @@ public static class ArtemisBootstrapper
|
|||||||
configureServices?.Invoke(_container);
|
configureServices?.Invoke(_container);
|
||||||
|
|
||||||
_container.UseDryIocDependencyResolver();
|
_container.UseDryIocDependencyResolver();
|
||||||
|
|
||||||
Logger.Sink = _container.Resolve<SerilogAvaloniaSink>();
|
Logger.Sink = _container.Resolve<SerilogAvaloniaSink>();
|
||||||
return _container;
|
return _container;
|
||||||
}
|
}
|
||||||
@ -64,7 +64,7 @@ public static class ArtemisBootstrapper
|
|||||||
if (_application.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop)
|
if (_application.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Constants.StartupArguments = new ReadOnlyCollection<string>(new List<string>(desktop.Args));
|
Constants.StartupArguments = new ReadOnlyCollection<string>(desktop.Args != null ? new List<string>(desktop.Args) : new List<string>());
|
||||||
|
|
||||||
// Don't shut down when the last window closes, we might still be active in the tray
|
// Don't shut down when the last window closes, we might still be active in the tray
|
||||||
desktop.ShutdownMode = ShutdownMode.OnExplicitShutdown;
|
desktop.ShutdownMode = ShutdownMode.OnExplicitShutdown;
|
||||||
|
|||||||
1
src/Artemis.UI/Assets/Animations/busy.json
Normal file
1
src/Artemis.UI/Assets/Animations/busy.json
Normal file
File diff suppressed because one or more lines are too long
@ -1,6 +1,7 @@
|
|||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
using Artemis.UI.DryIoc.Factories;
|
using Artemis.UI.DryIoc.Factories;
|
||||||
using Artemis.UI.DryIoc.InstanceProviders;
|
using Artemis.UI.DryIoc.InstanceProviders;
|
||||||
|
using Artemis.UI.Screens.Device.Layout.LayoutProviders;
|
||||||
using Artemis.UI.Screens.VisualScripting;
|
using Artemis.UI.Screens.VisualScripting;
|
||||||
using Artemis.UI.Services.Interfaces;
|
using Artemis.UI.Services.Interfaces;
|
||||||
using Artemis.UI.Services.Updating;
|
using Artemis.UI.Services.Updating;
|
||||||
@ -26,6 +27,7 @@ public static class ContainerExtensions
|
|||||||
|
|
||||||
container.RegisterMany(thisAssembly, type => type.IsAssignableTo<ViewModelBase>(), setup: Setup.With(preventDisposal: true));
|
container.RegisterMany(thisAssembly, type => type.IsAssignableTo<ViewModelBase>(), setup: Setup.With(preventDisposal: true));
|
||||||
container.RegisterMany(thisAssembly, type => type.IsAssignableTo<IToolViewModel>() && type.IsInterface, setup: Setup.With(preventDisposal: true));
|
container.RegisterMany(thisAssembly, type => type.IsAssignableTo<IToolViewModel>() && type.IsInterface, setup: Setup.With(preventDisposal: true));
|
||||||
|
container.RegisterMany(thisAssembly, type => type.IsAssignableTo<ILayoutProviderViewModel>() && type.IsInterface, setup: Setup.With(preventDisposal: true));
|
||||||
container.RegisterMany(thisAssembly, type => type.IsAssignableTo<IVmFactory>() && type != typeof(PropertyVmFactory));
|
container.RegisterMany(thisAssembly, type => type.IsAssignableTo<IVmFactory>() && type != typeof(PropertyVmFactory));
|
||||||
|
|
||||||
container.Register<NodeScriptWindowViewModelBase, NodeScriptWindowViewModel>(Reuse.Singleton);
|
container.Register<NodeScriptWindowViewModelBase, NodeScriptWindowViewModel>(Reuse.Singleton);
|
||||||
|
|||||||
@ -1,13 +1,14 @@
|
|||||||
using System;
|
using System.Collections.ObjectModel;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Reactive;
|
using System.Reactive;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.LayerBrushes;
|
using Artemis.Core.LayerBrushes;
|
||||||
using Artemis.Core.LayerEffects;
|
using Artemis.Core.LayerEffects;
|
||||||
using Artemis.Core.ScriptingProviders;
|
using Artemis.Core.ScriptingProviders;
|
||||||
using Artemis.UI.Routing;
|
|
||||||
using Artemis.UI.Screens.Device;
|
using Artemis.UI.Screens.Device;
|
||||||
|
using Artemis.UI.Screens.Device.General;
|
||||||
|
using Artemis.UI.Screens.Device.InputMappings;
|
||||||
|
using Artemis.UI.Screens.Device.Layout;
|
||||||
|
using Artemis.UI.Screens.Device.Leds;
|
||||||
using Artemis.UI.Screens.Plugins;
|
using Artemis.UI.Screens.Plugins;
|
||||||
using Artemis.UI.Screens.Plugins.Features;
|
using Artemis.UI.Screens.Plugins.Features;
|
||||||
using Artemis.UI.Screens.Plugins.Prerequisites;
|
using Artemis.UI.Screens.Plugins.Prerequisites;
|
||||||
@ -27,12 +28,8 @@ using Artemis.UI.Screens.Sidebar;
|
|||||||
using Artemis.UI.Screens.SurfaceEditor;
|
using Artemis.UI.Screens.SurfaceEditor;
|
||||||
using Artemis.UI.Screens.VisualScripting;
|
using Artemis.UI.Screens.VisualScripting;
|
||||||
using Artemis.UI.Screens.VisualScripting.Pins;
|
using Artemis.UI.Screens.VisualScripting.Pins;
|
||||||
using Artemis.UI.Shared;
|
|
||||||
using Artemis.UI.Shared.Routing;
|
|
||||||
using Artemis.WebClient.Updating;
|
using Artemis.WebClient.Updating;
|
||||||
using DryIoc;
|
using DryIoc;
|
||||||
using DynamicData;
|
|
||||||
using Material.Icons;
|
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.DryIoc.Factories;
|
namespace Artemis.UI.DryIoc.Factories;
|
||||||
@ -51,48 +48,49 @@ public interface IDeviceVmFactory : IVmFactory
|
|||||||
InputMappingsTabViewModel InputMappingsTabViewModel(ArtemisDevice device, ObservableCollection<ArtemisLed> selectedLeds);
|
InputMappingsTabViewModel InputMappingsTabViewModel(ArtemisDevice device, ObservableCollection<ArtemisLed> selectedLeds);
|
||||||
DeviceGeneralTabViewModel DeviceGeneralTabViewModel(ArtemisDevice device);
|
DeviceGeneralTabViewModel DeviceGeneralTabViewModel(ArtemisDevice device);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DeviceFactory : IDeviceVmFactory
|
public class DeviceFactory : IDeviceVmFactory
|
||||||
{
|
{
|
||||||
private readonly IContainer _container;
|
private readonly IContainer _container;
|
||||||
|
|
||||||
public DeviceFactory(IContainer container)
|
public DeviceFactory(IContainer container)
|
||||||
{
|
{
|
||||||
_container = container;
|
_container = container;
|
||||||
}
|
}
|
||||||
|
|
||||||
public DevicePropertiesViewModel DevicePropertiesViewModel(ArtemisDevice device)
|
public DevicePropertiesViewModel DevicePropertiesViewModel(ArtemisDevice device)
|
||||||
{
|
{
|
||||||
return _container.Resolve<DevicePropertiesViewModel>(new object[] { device });
|
return _container.Resolve<DevicePropertiesViewModel>(new object[] {device});
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeviceSettingsViewModel DeviceSettingsViewModel(ArtemisDevice device, DevicesTabViewModel devicesTabViewModel)
|
public DeviceSettingsViewModel DeviceSettingsViewModel(ArtemisDevice device, DevicesTabViewModel devicesTabViewModel)
|
||||||
{
|
{
|
||||||
return _container.Resolve<DeviceSettingsViewModel>(new object[] { device, devicesTabViewModel });
|
return _container.Resolve<DeviceSettingsViewModel>(new object[] {device, devicesTabViewModel});
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeviceDetectInputViewModel DeviceDetectInputViewModel(ArtemisDevice device)
|
public DeviceDetectInputViewModel DeviceDetectInputViewModel(ArtemisDevice device)
|
||||||
{
|
{
|
||||||
return _container.Resolve<DeviceDetectInputViewModel>(new object[] { device });
|
return _container.Resolve<DeviceDetectInputViewModel>(new object[] {device});
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeviceLayoutTabViewModel DeviceLayoutTabViewModel(ArtemisDevice device)
|
public DeviceLayoutTabViewModel DeviceLayoutTabViewModel(ArtemisDevice device)
|
||||||
{
|
{
|
||||||
return _container.Resolve<DeviceLayoutTabViewModel>(new object[] { device });
|
return _container.Resolve<DeviceLayoutTabViewModel>(new object[] {device});
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeviceLedsTabViewModel DeviceLedsTabViewModel(ArtemisDevice device, ObservableCollection<ArtemisLed> selectedLeds)
|
public DeviceLedsTabViewModel DeviceLedsTabViewModel(ArtemisDevice device, ObservableCollection<ArtemisLed> selectedLeds)
|
||||||
{
|
{
|
||||||
return _container.Resolve<DeviceLedsTabViewModel>(new object[] { device, selectedLeds });
|
return _container.Resolve<DeviceLedsTabViewModel>(new object[] {device, selectedLeds});
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputMappingsTabViewModel InputMappingsTabViewModel(ArtemisDevice device, ObservableCollection<ArtemisLed> selectedLeds)
|
public InputMappingsTabViewModel InputMappingsTabViewModel(ArtemisDevice device, ObservableCollection<ArtemisLed> selectedLeds)
|
||||||
{
|
{
|
||||||
return _container.Resolve<InputMappingsTabViewModel>(new object[] { device, selectedLeds });
|
return _container.Resolve<InputMappingsTabViewModel>(new object[] {device, selectedLeds});
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeviceGeneralTabViewModel DeviceGeneralTabViewModel(ArtemisDevice device)
|
public DeviceGeneralTabViewModel DeviceGeneralTabViewModel(ArtemisDevice device)
|
||||||
{
|
{
|
||||||
return _container.Resolve<DeviceGeneralTabViewModel>(new object[] { device });
|
return _container.Resolve<DeviceGeneralTabViewModel>(new object[] {device});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -102,28 +100,29 @@ public interface ISettingsVmFactory : IVmFactory
|
|||||||
PluginViewModel PluginViewModel(Plugin plugin, ReactiveCommand<Unit, Unit>? reload);
|
PluginViewModel PluginViewModel(Plugin plugin, ReactiveCommand<Unit, Unit>? reload);
|
||||||
PluginFeatureViewModel PluginFeatureViewModel(PluginFeatureInfo pluginFeatureInfo, bool showShield);
|
PluginFeatureViewModel PluginFeatureViewModel(PluginFeatureInfo pluginFeatureInfo, bool showShield);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SettingsVmFactory : ISettingsVmFactory
|
public class SettingsVmFactory : ISettingsVmFactory
|
||||||
{
|
{
|
||||||
private readonly IContainer _container;
|
private readonly IContainer _container;
|
||||||
|
|
||||||
public SettingsVmFactory(IContainer container)
|
public SettingsVmFactory(IContainer container)
|
||||||
{
|
{
|
||||||
_container = container;
|
_container = container;
|
||||||
}
|
}
|
||||||
|
|
||||||
public PluginSettingsViewModel PluginSettingsViewModel(Plugin plugin)
|
public PluginSettingsViewModel PluginSettingsViewModel(Plugin plugin)
|
||||||
{
|
{
|
||||||
return _container.Resolve<PluginSettingsViewModel>(new object[] { plugin });
|
return _container.Resolve<PluginSettingsViewModel>(new object[] {plugin});
|
||||||
}
|
}
|
||||||
|
|
||||||
public PluginViewModel PluginViewModel(Plugin plugin, ReactiveCommand<Unit, Unit>? reload)
|
public PluginViewModel PluginViewModel(Plugin plugin, ReactiveCommand<Unit, Unit>? reload)
|
||||||
{
|
{
|
||||||
return _container.Resolve<PluginViewModel>(new object?[] { plugin, reload });
|
return _container.Resolve<PluginViewModel>(new object?[] {plugin, reload});
|
||||||
}
|
}
|
||||||
|
|
||||||
public PluginFeatureViewModel PluginFeatureViewModel(PluginFeatureInfo pluginFeatureInfo, bool showShield)
|
public PluginFeatureViewModel PluginFeatureViewModel(PluginFeatureInfo pluginFeatureInfo, bool showShield)
|
||||||
{
|
{
|
||||||
return _container.Resolve<PluginFeatureViewModel>(new object[] { pluginFeatureInfo, showShield });
|
return _container.Resolve<PluginFeatureViewModel>(new object[] {pluginFeatureInfo, showShield});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -132,31 +131,33 @@ public interface ISidebarVmFactory : IVmFactory
|
|||||||
SidebarCategoryViewModel SidebarCategoryViewModel(ProfileCategory profileCategory);
|
SidebarCategoryViewModel SidebarCategoryViewModel(ProfileCategory profileCategory);
|
||||||
SidebarProfileConfigurationViewModel SidebarProfileConfigurationViewModel(ProfileConfiguration profileConfiguration);
|
SidebarProfileConfigurationViewModel SidebarProfileConfigurationViewModel(ProfileConfiguration profileConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SidebarVmFactory : ISidebarVmFactory
|
public class SidebarVmFactory : ISidebarVmFactory
|
||||||
{
|
{
|
||||||
private readonly IContainer _container;
|
private readonly IContainer _container;
|
||||||
|
|
||||||
public SidebarVmFactory(IContainer container)
|
public SidebarVmFactory(IContainer container)
|
||||||
{
|
{
|
||||||
_container = container;
|
_container = container;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SidebarCategoryViewModel SidebarCategoryViewModel(ProfileCategory profileCategory)
|
public SidebarCategoryViewModel SidebarCategoryViewModel(ProfileCategory profileCategory)
|
||||||
{
|
{
|
||||||
return _container.Resolve<SidebarCategoryViewModel>(new object[] { profileCategory });
|
return _container.Resolve<SidebarCategoryViewModel>(new object[] {profileCategory});
|
||||||
}
|
}
|
||||||
|
|
||||||
public SidebarProfileConfigurationViewModel SidebarProfileConfigurationViewModel(ProfileConfiguration profileConfiguration)
|
public SidebarProfileConfigurationViewModel SidebarProfileConfigurationViewModel(ProfileConfiguration profileConfiguration)
|
||||||
{
|
{
|
||||||
return _container.Resolve<SidebarProfileConfigurationViewModel>(new object[] { profileConfiguration });
|
return _container.Resolve<SidebarProfileConfigurationViewModel>(new object[] {profileConfiguration});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface ISurfaceVmFactory : IVmFactory
|
public interface ISurfaceVmFactory : IVmFactory
|
||||||
{
|
{
|
||||||
SurfaceDeviceViewModel SurfaceDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel);
|
SurfaceDeviceViewModel SurfaceDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel);
|
||||||
ListDeviceViewModel ListDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel);
|
ListDeviceViewModel ListDeviceViewModel(ArtemisDevice device);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class SurfaceVmFactory : ISurfaceVmFactory
|
public class SurfaceVmFactory : ISurfaceVmFactory
|
||||||
{
|
{
|
||||||
private readonly IContainer _container;
|
private readonly IContainer _container;
|
||||||
@ -168,12 +169,12 @@ public class SurfaceVmFactory : ISurfaceVmFactory
|
|||||||
|
|
||||||
public SurfaceDeviceViewModel SurfaceDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel)
|
public SurfaceDeviceViewModel SurfaceDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel)
|
||||||
{
|
{
|
||||||
return _container.Resolve<SurfaceDeviceViewModel>(new object[] { device, surfaceEditorViewModel });
|
return _container.Resolve<SurfaceDeviceViewModel>(new object[] {device, surfaceEditorViewModel});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ListDeviceViewModel ListDeviceViewModel(ArtemisDevice device, SurfaceEditorViewModel surfaceEditorViewModel)
|
public ListDeviceViewModel ListDeviceViewModel(ArtemisDevice device)
|
||||||
{
|
{
|
||||||
return _container.Resolve<ListDeviceViewModel>(new object[] { device, surfaceEditorViewModel });
|
return _container.Resolve<ListDeviceViewModel>(new object[] {device});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -181,6 +182,7 @@ public interface IPrerequisitesVmFactory : IVmFactory
|
|||||||
{
|
{
|
||||||
PluginPrerequisiteViewModel PluginPrerequisiteViewModel(PluginPrerequisite pluginPrerequisite, bool uninstall);
|
PluginPrerequisiteViewModel PluginPrerequisiteViewModel(PluginPrerequisite pluginPrerequisite, bool uninstall);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class PrerequisitesVmFactory : IPrerequisitesVmFactory
|
public class PrerequisitesVmFactory : IPrerequisitesVmFactory
|
||||||
{
|
{
|
||||||
private readonly IContainer _container;
|
private readonly IContainer _container;
|
||||||
@ -192,7 +194,7 @@ public class PrerequisitesVmFactory : IPrerequisitesVmFactory
|
|||||||
|
|
||||||
public PluginPrerequisiteViewModel PluginPrerequisiteViewModel(PluginPrerequisite pluginPrerequisite, bool uninstall)
|
public PluginPrerequisiteViewModel PluginPrerequisiteViewModel(PluginPrerequisite pluginPrerequisite, bool uninstall)
|
||||||
{
|
{
|
||||||
return _container.Resolve<PluginPrerequisiteViewModel>(new object[] { pluginPrerequisite, uninstall });
|
return _container.Resolve<PluginPrerequisiteViewModel>(new object[] {pluginPrerequisite, uninstall});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -204,6 +206,7 @@ public interface IProfileEditorVmFactory : IVmFactory
|
|||||||
LayerShapeVisualizerViewModel LayerShapeVisualizerViewModel(Layer layer);
|
LayerShapeVisualizerViewModel LayerShapeVisualizerViewModel(Layer layer);
|
||||||
LayerVisualizerViewModel LayerVisualizerViewModel(Layer layer);
|
LayerVisualizerViewModel LayerVisualizerViewModel(Layer layer);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ProfileEditorVmFactory : IProfileEditorVmFactory
|
public class ProfileEditorVmFactory : IProfileEditorVmFactory
|
||||||
{
|
{
|
||||||
private readonly IContainer _container;
|
private readonly IContainer _container;
|
||||||
@ -215,27 +218,27 @@ public class ProfileEditorVmFactory : IProfileEditorVmFactory
|
|||||||
|
|
||||||
public FolderTreeItemViewModel FolderTreeItemViewModel(TreeItemViewModel? parent, Folder folder)
|
public FolderTreeItemViewModel FolderTreeItemViewModel(TreeItemViewModel? parent, Folder folder)
|
||||||
{
|
{
|
||||||
return _container.Resolve<FolderTreeItemViewModel>(new object?[] { parent, folder });
|
return _container.Resolve<FolderTreeItemViewModel>(new object?[] {parent, folder});
|
||||||
}
|
}
|
||||||
|
|
||||||
public LayerShapeVisualizerViewModel LayerShapeVisualizerViewModel(Layer layer)
|
public LayerShapeVisualizerViewModel LayerShapeVisualizerViewModel(Layer layer)
|
||||||
{
|
{
|
||||||
return _container.Resolve<LayerShapeVisualizerViewModel>(new object[] { layer });
|
return _container.Resolve<LayerShapeVisualizerViewModel>(new object[] {layer});
|
||||||
}
|
}
|
||||||
|
|
||||||
public LayerTreeItemViewModel LayerTreeItemViewModel(TreeItemViewModel? parent, Layer layer)
|
public LayerTreeItemViewModel LayerTreeItemViewModel(TreeItemViewModel? parent, Layer layer)
|
||||||
{
|
{
|
||||||
return _container.Resolve<LayerTreeItemViewModel>(new object?[] { parent, layer });
|
return _container.Resolve<LayerTreeItemViewModel>(new object?[] {parent, layer});
|
||||||
}
|
}
|
||||||
|
|
||||||
public LayerVisualizerViewModel LayerVisualizerViewModel(Layer layer)
|
public LayerVisualizerViewModel LayerVisualizerViewModel(Layer layer)
|
||||||
{
|
{
|
||||||
return _container.Resolve<LayerVisualizerViewModel>(new object[] { layer });
|
return _container.Resolve<LayerVisualizerViewModel>(new object[] {layer});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ProfileEditorViewModel ProfileEditorViewModel(IScreen hostScreen)
|
public ProfileEditorViewModel ProfileEditorViewModel(IScreen hostScreen)
|
||||||
{
|
{
|
||||||
return _container.Resolve<ProfileEditorViewModel>(new object[] { hostScreen });
|
return _container.Resolve<ProfileEditorViewModel>(new object[] {hostScreen});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -251,6 +254,7 @@ public interface ILayerPropertyVmFactory : IVmFactory
|
|||||||
TimelineViewModel TimelineViewModel(ObservableCollection<PropertyGroupViewModel> propertyGroupViewModels);
|
TimelineViewModel TimelineViewModel(ObservableCollection<PropertyGroupViewModel> propertyGroupViewModels);
|
||||||
TimelineGroupViewModel TimelineGroupViewModel(PropertyGroupViewModel propertyGroupViewModel);
|
TimelineGroupViewModel TimelineGroupViewModel(PropertyGroupViewModel propertyGroupViewModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class LayerPropertyVmFactory : ILayerPropertyVmFactory
|
public class LayerPropertyVmFactory : ILayerPropertyVmFactory
|
||||||
{
|
{
|
||||||
private readonly IContainer _container;
|
private readonly IContainer _container;
|
||||||
@ -262,37 +266,37 @@ public class LayerPropertyVmFactory : ILayerPropertyVmFactory
|
|||||||
|
|
||||||
public PropertyViewModel PropertyViewModel(ILayerProperty layerProperty)
|
public PropertyViewModel PropertyViewModel(ILayerProperty layerProperty)
|
||||||
{
|
{
|
||||||
return _container.Resolve<PropertyViewModel>(new object[] { layerProperty });
|
return _container.Resolve<PropertyViewModel>(new object[] {layerProperty});
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup)
|
public PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup)
|
||||||
{
|
{
|
||||||
return _container.Resolve<PropertyGroupViewModel>(new object[] { layerPropertyGroup });
|
return _container.Resolve<PropertyGroupViewModel>(new object[] {layerPropertyGroup});
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, BaseLayerBrush layerBrush)
|
public PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, BaseLayerBrush layerBrush)
|
||||||
{
|
{
|
||||||
return _container.Resolve<PropertyGroupViewModel>(new object[] { layerPropertyGroup, layerBrush });
|
return _container.Resolve<PropertyGroupViewModel>(new object[] {layerPropertyGroup, layerBrush});
|
||||||
}
|
}
|
||||||
|
|
||||||
public PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, BaseLayerEffect layerEffect)
|
public PropertyGroupViewModel PropertyGroupViewModel(LayerPropertyGroup layerPropertyGroup, BaseLayerEffect layerEffect)
|
||||||
{
|
{
|
||||||
return _container.Resolve<PropertyGroupViewModel>(new object[] { layerPropertyGroup, layerEffect });
|
return _container.Resolve<PropertyGroupViewModel>(new object[] {layerPropertyGroup, layerEffect});
|
||||||
}
|
}
|
||||||
|
|
||||||
public TreeGroupViewModel TreeGroupViewModel(PropertyGroupViewModel propertyGroupViewModel)
|
public TreeGroupViewModel TreeGroupViewModel(PropertyGroupViewModel propertyGroupViewModel)
|
||||||
{
|
{
|
||||||
return _container.Resolve<TreeGroupViewModel>(new object[] { propertyGroupViewModel });
|
return _container.Resolve<TreeGroupViewModel>(new object[] {propertyGroupViewModel});
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimelineViewModel TimelineViewModel(ObservableCollection<PropertyGroupViewModel> propertyGroupViewModels)
|
public TimelineViewModel TimelineViewModel(ObservableCollection<PropertyGroupViewModel> propertyGroupViewModels)
|
||||||
{
|
{
|
||||||
return _container.Resolve<TimelineViewModel>(new object[] { propertyGroupViewModels });
|
return _container.Resolve<TimelineViewModel>(new object[] {propertyGroupViewModels});
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimelineGroupViewModel TimelineGroupViewModel(PropertyGroupViewModel propertyGroupViewModel)
|
public TimelineGroupViewModel TimelineGroupViewModel(PropertyGroupViewModel propertyGroupViewModel)
|
||||||
{
|
{
|
||||||
return _container.Resolve<TimelineGroupViewModel>(new object[] { propertyGroupViewModel });
|
return _container.Resolve<TimelineGroupViewModel>(new object[] {propertyGroupViewModel});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -300,6 +304,7 @@ public interface IDataBindingVmFactory : IVmFactory
|
|||||||
{
|
{
|
||||||
DataBindingViewModel DataBindingViewModel();
|
DataBindingViewModel DataBindingViewModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DataBindingVmFactory : IDataBindingVmFactory
|
public class DataBindingVmFactory : IDataBindingVmFactory
|
||||||
{
|
{
|
||||||
private readonly IContainer _container;
|
private readonly IContainer _container;
|
||||||
@ -333,6 +338,7 @@ public interface INodeVmFactory : IVmFactory
|
|||||||
InputPinCollectionViewModel InputPinCollectionViewModel(IPinCollection inputPinCollection, NodeScriptViewModel nodeScriptViewModel);
|
InputPinCollectionViewModel InputPinCollectionViewModel(IPinCollection inputPinCollection, NodeScriptViewModel nodeScriptViewModel);
|
||||||
OutputPinCollectionViewModel OutputPinCollectionViewModel(IPinCollection outputPinCollection, NodeScriptViewModel nodeScriptViewModel);
|
OutputPinCollectionViewModel OutputPinCollectionViewModel(IPinCollection outputPinCollection, NodeScriptViewModel nodeScriptViewModel);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class NodeVmFactory : INodeVmFactory
|
public class NodeVmFactory : INodeVmFactory
|
||||||
{
|
{
|
||||||
private readonly IContainer _container;
|
private readonly IContainer _container;
|
||||||
@ -344,47 +350,47 @@ public class NodeVmFactory : INodeVmFactory
|
|||||||
|
|
||||||
public NodeScriptViewModel NodeScriptViewModel(NodeScript nodeScript, bool isPreview)
|
public NodeScriptViewModel NodeScriptViewModel(NodeScript nodeScript, bool isPreview)
|
||||||
{
|
{
|
||||||
return _container.Resolve<NodeScriptViewModel>(new object[] { nodeScript, isPreview });
|
return _container.Resolve<NodeScriptViewModel>(new object[] {nodeScript, isPreview});
|
||||||
}
|
}
|
||||||
|
|
||||||
public NodePickerViewModel NodePickerViewModel(NodeScript nodeScript)
|
public NodePickerViewModel NodePickerViewModel(NodeScript nodeScript)
|
||||||
{
|
{
|
||||||
return _container.Resolve<NodePickerViewModel>(new object[] { nodeScript });
|
return _container.Resolve<NodePickerViewModel>(new object[] {nodeScript});
|
||||||
}
|
}
|
||||||
|
|
||||||
public NodeViewModel NodeViewModel(NodeScriptViewModel nodeScriptViewModel, INode node)
|
public NodeViewModel NodeViewModel(NodeScriptViewModel nodeScriptViewModel, INode node)
|
||||||
{
|
{
|
||||||
return _container.Resolve<NodeViewModel>(new object[] { nodeScriptViewModel, node });
|
return _container.Resolve<NodeViewModel>(new object[] {nodeScriptViewModel, node});
|
||||||
}
|
}
|
||||||
|
|
||||||
public CableViewModel CableViewModel(NodeScriptViewModel nodeScriptViewModel, IPin from, IPin to)
|
public CableViewModel CableViewModel(NodeScriptViewModel nodeScriptViewModel, IPin from, IPin to)
|
||||||
{
|
{
|
||||||
return _container.Resolve<CableViewModel>(new object[] { nodeScriptViewModel, from, to });
|
return _container.Resolve<CableViewModel>(new object[] {nodeScriptViewModel, from, to});
|
||||||
}
|
}
|
||||||
|
|
||||||
public DragCableViewModel DragCableViewModel(PinViewModel pinViewModel)
|
public DragCableViewModel DragCableViewModel(PinViewModel pinViewModel)
|
||||||
{
|
{
|
||||||
return _container.Resolve<DragCableViewModel>(new object[] { pinViewModel });
|
return _container.Resolve<DragCableViewModel>(new object[] {pinViewModel});
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputPinViewModel InputPinViewModel(IPin inputPin, NodeScriptViewModel nodeScriptViewModel)
|
public InputPinViewModel InputPinViewModel(IPin inputPin, NodeScriptViewModel nodeScriptViewModel)
|
||||||
{
|
{
|
||||||
return _container.Resolve<InputPinViewModel>(new object[] { inputPin, nodeScriptViewModel });
|
return _container.Resolve<InputPinViewModel>(new object[] {inputPin, nodeScriptViewModel});
|
||||||
}
|
}
|
||||||
|
|
||||||
public OutputPinViewModel OutputPinViewModel(IPin outputPin, NodeScriptViewModel nodeScriptViewModel)
|
public OutputPinViewModel OutputPinViewModel(IPin outputPin, NodeScriptViewModel nodeScriptViewModel)
|
||||||
{
|
{
|
||||||
return _container.Resolve<OutputPinViewModel>(new object[] { outputPin, nodeScriptViewModel });
|
return _container.Resolve<OutputPinViewModel>(new object[] {outputPin, nodeScriptViewModel});
|
||||||
}
|
}
|
||||||
|
|
||||||
public InputPinCollectionViewModel InputPinCollectionViewModel(IPinCollection inputPinCollection, NodeScriptViewModel nodeScriptViewModel)
|
public InputPinCollectionViewModel InputPinCollectionViewModel(IPinCollection inputPinCollection, NodeScriptViewModel nodeScriptViewModel)
|
||||||
{
|
{
|
||||||
return _container.Resolve<InputPinCollectionViewModel>(new object[] { inputPinCollection, nodeScriptViewModel });
|
return _container.Resolve<InputPinCollectionViewModel>(new object[] {inputPinCollection, nodeScriptViewModel});
|
||||||
}
|
}
|
||||||
|
|
||||||
public OutputPinCollectionViewModel OutputPinCollectionViewModel(IPinCollection outputPinCollection, NodeScriptViewModel nodeScriptViewModel)
|
public OutputPinCollectionViewModel OutputPinCollectionViewModel(IPinCollection outputPinCollection, NodeScriptViewModel nodeScriptViewModel)
|
||||||
{
|
{
|
||||||
return _container.Resolve<OutputPinCollectionViewModel>(new object[] { outputPinCollection, nodeScriptViewModel });
|
return _container.Resolve<OutputPinCollectionViewModel>(new object[] {outputPinCollection, nodeScriptViewModel});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -395,6 +401,7 @@ public interface IConditionVmFactory : IVmFactory
|
|||||||
StaticConditionViewModel StaticConditionViewModel(StaticCondition staticCondition);
|
StaticConditionViewModel StaticConditionViewModel(StaticCondition staticCondition);
|
||||||
EventConditionViewModel EventConditionViewModel(EventCondition eventCondition);
|
EventConditionViewModel EventConditionViewModel(EventCondition eventCondition);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ConditionVmFactory : IConditionVmFactory
|
public class ConditionVmFactory : IConditionVmFactory
|
||||||
{
|
{
|
||||||
private readonly IContainer _container;
|
private readonly IContainer _container;
|
||||||
@ -406,22 +413,22 @@ public class ConditionVmFactory : IConditionVmFactory
|
|||||||
|
|
||||||
public AlwaysOnConditionViewModel AlwaysOnConditionViewModel(AlwaysOnCondition alwaysOnCondition)
|
public AlwaysOnConditionViewModel AlwaysOnConditionViewModel(AlwaysOnCondition alwaysOnCondition)
|
||||||
{
|
{
|
||||||
return _container.Resolve<AlwaysOnConditionViewModel>(new object[] { alwaysOnCondition });
|
return _container.Resolve<AlwaysOnConditionViewModel>(new object[] {alwaysOnCondition});
|
||||||
}
|
}
|
||||||
|
|
||||||
public PlayOnceConditionViewModel PlayOnceConditionViewModel(PlayOnceCondition playOnceCondition)
|
public PlayOnceConditionViewModel PlayOnceConditionViewModel(PlayOnceCondition playOnceCondition)
|
||||||
{
|
{
|
||||||
return _container.Resolve<PlayOnceConditionViewModel>(new object[] { playOnceCondition });
|
return _container.Resolve<PlayOnceConditionViewModel>(new object[] {playOnceCondition});
|
||||||
}
|
}
|
||||||
|
|
||||||
public StaticConditionViewModel StaticConditionViewModel(StaticCondition staticCondition)
|
public StaticConditionViewModel StaticConditionViewModel(StaticCondition staticCondition)
|
||||||
{
|
{
|
||||||
return _container.Resolve<StaticConditionViewModel>(new object[] { staticCondition });
|
return _container.Resolve<StaticConditionViewModel>(new object[] {staticCondition});
|
||||||
}
|
}
|
||||||
|
|
||||||
public EventConditionViewModel EventConditionViewModel(EventCondition eventCondition)
|
public EventConditionViewModel EventConditionViewModel(EventCondition eventCondition)
|
||||||
{
|
{
|
||||||
return _container.Resolve<EventConditionViewModel>(new object[] { eventCondition });
|
return _container.Resolve<EventConditionViewModel>(new object[] {eventCondition});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,6 +439,7 @@ public interface ILayerHintVmFactory : IVmFactory
|
|||||||
KeyboardSectionAdaptionHintViewModel KeyboardSectionAdaptionHintViewModel(Layer layer, KeyboardSectionAdaptionHint adaptionHint);
|
KeyboardSectionAdaptionHintViewModel KeyboardSectionAdaptionHintViewModel(Layer layer, KeyboardSectionAdaptionHint adaptionHint);
|
||||||
SingleLedAdaptionHintViewModel SingleLedAdaptionHintViewModel(Layer layer, SingleLedAdaptionHint adaptionHint);
|
SingleLedAdaptionHintViewModel SingleLedAdaptionHintViewModel(Layer layer, SingleLedAdaptionHint adaptionHint);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class LayerHintVmFactory : ILayerHintVmFactory
|
public class LayerHintVmFactory : ILayerHintVmFactory
|
||||||
{
|
{
|
||||||
private readonly IContainer _container;
|
private readonly IContainer _container;
|
||||||
@ -443,22 +451,22 @@ public class LayerHintVmFactory : ILayerHintVmFactory
|
|||||||
|
|
||||||
public CategoryAdaptionHintViewModel CategoryAdaptionHintViewModel(Layer layer, CategoryAdaptionHint adaptionHint)
|
public CategoryAdaptionHintViewModel CategoryAdaptionHintViewModel(Layer layer, CategoryAdaptionHint adaptionHint)
|
||||||
{
|
{
|
||||||
return _container.Resolve<CategoryAdaptionHintViewModel>(new object[] { layer, adaptionHint });
|
return _container.Resolve<CategoryAdaptionHintViewModel>(new object[] {layer, adaptionHint});
|
||||||
}
|
}
|
||||||
|
|
||||||
public DeviceAdaptionHintViewModel DeviceAdaptionHintViewModel(Layer layer, DeviceAdaptionHint adaptionHint)
|
public DeviceAdaptionHintViewModel DeviceAdaptionHintViewModel(Layer layer, DeviceAdaptionHint adaptionHint)
|
||||||
{
|
{
|
||||||
return _container.Resolve<DeviceAdaptionHintViewModel>(new object[] { layer, adaptionHint });
|
return _container.Resolve<DeviceAdaptionHintViewModel>(new object[] {layer, adaptionHint});
|
||||||
}
|
}
|
||||||
|
|
||||||
public KeyboardSectionAdaptionHintViewModel KeyboardSectionAdaptionHintViewModel(Layer layer, KeyboardSectionAdaptionHint adaptionHint)
|
public KeyboardSectionAdaptionHintViewModel KeyboardSectionAdaptionHintViewModel(Layer layer, KeyboardSectionAdaptionHint adaptionHint)
|
||||||
{
|
{
|
||||||
return _container.Resolve<KeyboardSectionAdaptionHintViewModel>(new object[] { layer, adaptionHint });
|
return _container.Resolve<KeyboardSectionAdaptionHintViewModel>(new object[] {layer, adaptionHint});
|
||||||
}
|
}
|
||||||
|
|
||||||
public SingleLedAdaptionHintViewModel SingleLedAdaptionHintViewModel(Layer layer, SingleLedAdaptionHint adaptionHint)
|
public SingleLedAdaptionHintViewModel SingleLedAdaptionHintViewModel(Layer layer, SingleLedAdaptionHint adaptionHint)
|
||||||
{
|
{
|
||||||
return _container.Resolve<SingleLedAdaptionHintViewModel>(new object[] { layer, adaptionHint });
|
return _container.Resolve<SingleLedAdaptionHintViewModel>(new object[] {layer, adaptionHint});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -467,6 +475,7 @@ public interface IScriptVmFactory : IVmFactory
|
|||||||
ScriptConfigurationViewModel ScriptConfigurationViewModel(ScriptConfiguration scriptConfiguration);
|
ScriptConfigurationViewModel ScriptConfigurationViewModel(ScriptConfiguration scriptConfiguration);
|
||||||
ScriptConfigurationViewModel ScriptConfigurationViewModel(Profile profile, ScriptConfiguration scriptConfiguration);
|
ScriptConfigurationViewModel ScriptConfigurationViewModel(Profile profile, ScriptConfiguration scriptConfiguration);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ScriptVmFactory : IScriptVmFactory
|
public class ScriptVmFactory : IScriptVmFactory
|
||||||
{
|
{
|
||||||
private readonly IContainer _container;
|
private readonly IContainer _container;
|
||||||
@ -478,12 +487,12 @@ public class ScriptVmFactory : IScriptVmFactory
|
|||||||
|
|
||||||
public ScriptConfigurationViewModel ScriptConfigurationViewModel(ScriptConfiguration scriptConfiguration)
|
public ScriptConfigurationViewModel ScriptConfigurationViewModel(ScriptConfiguration scriptConfiguration)
|
||||||
{
|
{
|
||||||
return _container.Resolve<ScriptConfigurationViewModel>(new object[] { scriptConfiguration });
|
return _container.Resolve<ScriptConfigurationViewModel>(new object[] {scriptConfiguration});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScriptConfigurationViewModel ScriptConfigurationViewModel(Profile profile, ScriptConfiguration scriptConfiguration)
|
public ScriptConfigurationViewModel ScriptConfigurationViewModel(Profile profile, ScriptConfiguration scriptConfiguration)
|
||||||
{
|
{
|
||||||
return _container.Resolve<ScriptConfigurationViewModel>(new object[] { profile, scriptConfiguration });
|
return _container.Resolve<ScriptConfigurationViewModel>(new object[] {profile, scriptConfiguration});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -491,6 +500,7 @@ public interface IReleaseVmFactory : IVmFactory
|
|||||||
{
|
{
|
||||||
ReleaseViewModel ReleaseListViewModel(IGetReleases_PublishedReleases_Nodes release);
|
ReleaseViewModel ReleaseListViewModel(IGetReleases_PublishedReleases_Nodes release);
|
||||||
}
|
}
|
||||||
|
|
||||||
public class ReleaseVmFactory : IReleaseVmFactory
|
public class ReleaseVmFactory : IReleaseVmFactory
|
||||||
{
|
{
|
||||||
private readonly IContainer _container;
|
private readonly IContainer _container;
|
||||||
@ -499,9 +509,9 @@ public class ReleaseVmFactory : IReleaseVmFactory
|
|||||||
{
|
{
|
||||||
_container = container;
|
_container = container;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ReleaseViewModel ReleaseListViewModel(IGetReleases_PublishedReleases_Nodes release)
|
public ReleaseViewModel ReleaseListViewModel(IGetReleases_PublishedReleases_Nodes release)
|
||||||
{
|
{
|
||||||
return _container.Resolve<ReleaseViewModel>(new object[] { release });
|
return _container.Resolve<ReleaseViewModel>(new object[] {release});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -6,32 +6,28 @@ using Artemis.UI.Screens.Debugger.Logs;
|
|||||||
using Artemis.UI.Screens.Debugger.Performance;
|
using Artemis.UI.Screens.Debugger.Performance;
|
||||||
using Artemis.UI.Screens.Debugger.Render;
|
using Artemis.UI.Screens.Debugger.Render;
|
||||||
using Artemis.UI.Screens.Debugger.Routing;
|
using Artemis.UI.Screens.Debugger.Routing;
|
||||||
|
using Artemis.UI.Screens.Debugger.Workshop;
|
||||||
using Artemis.UI.Services.Interfaces;
|
using Artemis.UI.Services.Interfaces;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Debugger;
|
namespace Artemis.UI.Screens.Debugger;
|
||||||
|
|
||||||
public class DebugViewModel : ActivatableViewModelBase, IScreen
|
public partial class DebugViewModel : ActivatableViewModelBase, IScreen
|
||||||
{
|
{
|
||||||
private ViewModelBase _selectedItem;
|
[Notify] private ViewModelBase _selectedItem;
|
||||||
|
|
||||||
public DebugViewModel(IDebugService debugService, RenderDebugViewModel render, DataModelDebugViewModel dataModel, PerformanceDebugViewModel performance, RoutingDebugViewModel routing, LogsDebugViewModel logs)
|
public DebugViewModel(IDebugService debugService, RenderDebugViewModel render, DataModelDebugViewModel dataModel, PerformanceDebugViewModel performance, RoutingDebugViewModel routing, WorkshopDebugViewModel workshop, LogsDebugViewModel logs)
|
||||||
{
|
{
|
||||||
Items = new ObservableCollection<ViewModelBase> {render, dataModel, performance, routing, logs};
|
Items = new ObservableCollection<ViewModelBase> {render, dataModel, performance, routing, workshop, logs};
|
||||||
_selectedItem = render;
|
_selectedItem = render;
|
||||||
|
|
||||||
this.WhenActivated(d => Disposable.Create(debugService.ClearDebugger).DisposeWith(d));
|
this.WhenActivated(d => Disposable.Create(debugService.ClearDebugger).DisposeWith(d));
|
||||||
}
|
}
|
||||||
|
|
||||||
public ObservableCollection<ViewModelBase> Items { get; }
|
public ObservableCollection<ViewModelBase> Items { get; }
|
||||||
|
|
||||||
public ViewModelBase SelectedItem
|
|
||||||
{
|
|
||||||
get => _selectedItem;
|
|
||||||
set => RaiseAndSetIfChanged(ref _selectedItem, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Activate()
|
public void Activate()
|
||||||
{
|
{
|
||||||
OnActivationRequested();
|
OnActivationRequested();
|
||||||
|
|||||||
@ -12,21 +12,21 @@ using Artemis.UI.Shared.DataModelVisualization.Shared;
|
|||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using DynamicData;
|
using DynamicData;
|
||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Debugger.DataModel;
|
namespace Artemis.UI.Screens.Debugger.DataModel;
|
||||||
|
|
||||||
public class DataModelDebugViewModel : ActivatableViewModelBase
|
public partial class DataModelDebugViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
private readonly IDataModelUIService _dataModelUIService;
|
private readonly IDataModelUIService _dataModelUIService;
|
||||||
private readonly IPluginManagementService _pluginManagementService;
|
private readonly IPluginManagementService _pluginManagementService;
|
||||||
private readonly DispatcherTimer _updateTimer;
|
private readonly DispatcherTimer _updateTimer;
|
||||||
|
|
||||||
private bool _isModuleFilterEnabled;
|
private bool _isModuleFilterEnabled;
|
||||||
private DataModelPropertiesViewModel? _mainDataModel;
|
|
||||||
private string? _propertySearch;
|
|
||||||
private Module? _selectedModule;
|
private Module? _selectedModule;
|
||||||
private bool _slowUpdates;
|
private bool _slowUpdates;
|
||||||
|
[Notify] private DataModelPropertiesViewModel? _mainDataModel;
|
||||||
|
[Notify] private string? _propertySearch;
|
||||||
|
|
||||||
public DataModelDebugViewModel(IDataModelUIService dataModelUIService, IPluginManagementService pluginManagementService)
|
public DataModelDebugViewModel(IDataModelUIService dataModelUIService, IPluginManagementService pluginManagementService)
|
||||||
{
|
{
|
||||||
@ -57,18 +57,6 @@ public class DataModelDebugViewModel : ActivatableViewModelBase
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public DataModelPropertiesViewModel? MainDataModel
|
|
||||||
{
|
|
||||||
get => _mainDataModel;
|
|
||||||
set => RaiseAndSetIfChanged(ref _mainDataModel, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string? PropertySearch
|
|
||||||
{
|
|
||||||
get => _propertySearch;
|
|
||||||
set => RaiseAndSetIfChanged(ref _propertySearch, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool SlowUpdates
|
public bool SlowUpdates
|
||||||
{
|
{
|
||||||
get => _slowUpdates;
|
get => _slowUpdates;
|
||||||
|
|||||||
@ -1,16 +1,17 @@
|
|||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Debugger.Performance;
|
namespace Artemis.UI.Screens.Debugger.Performance;
|
||||||
|
|
||||||
public class PerformanceDebugMeasurementViewModel : ViewModelBase
|
public partial class PerformanceDebugMeasurementViewModel : ViewModelBase
|
||||||
{
|
{
|
||||||
private string? _average;
|
[Notify] private string? _average;
|
||||||
private string? _last;
|
[Notify] private string? _last;
|
||||||
private string? _max;
|
[Notify] private string? _max;
|
||||||
private string? _min;
|
[Notify] private string? _min;
|
||||||
private string? _percentile;
|
[Notify] private string? _percentile;
|
||||||
private string? _count;
|
[Notify] private string? _count;
|
||||||
|
|
||||||
public PerformanceDebugMeasurementViewModel(ProfilingMeasurement measurement)
|
public PerformanceDebugMeasurementViewModel(ProfilingMeasurement measurement)
|
||||||
{
|
{
|
||||||
@ -19,42 +20,6 @@ public class PerformanceDebugMeasurementViewModel : ViewModelBase
|
|||||||
|
|
||||||
public ProfilingMeasurement Measurement { get; }
|
public ProfilingMeasurement Measurement { get; }
|
||||||
|
|
||||||
public string? Last
|
|
||||||
{
|
|
||||||
get => _last;
|
|
||||||
set => RaiseAndSetIfChanged(ref _last, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string? Average
|
|
||||||
{
|
|
||||||
get => _average;
|
|
||||||
set => RaiseAndSetIfChanged(ref _average, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string? Min
|
|
||||||
{
|
|
||||||
get => _min;
|
|
||||||
set => RaiseAndSetIfChanged(ref _min, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string? Max
|
|
||||||
{
|
|
||||||
get => _max;
|
|
||||||
set => RaiseAndSetIfChanged(ref _max, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string? Percentile
|
|
||||||
{
|
|
||||||
get => _percentile;
|
|
||||||
set => RaiseAndSetIfChanged(ref _percentile, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string? Count
|
|
||||||
{
|
|
||||||
get => _count;
|
|
||||||
set => RaiseAndSetIfChanged(ref _count, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Update()
|
public void Update()
|
||||||
{
|
{
|
||||||
Last = Measurement.GetLast().TotalMilliseconds + " ms";
|
Last = Measurement.GetLast().TotalMilliseconds + " ms";
|
||||||
|
|||||||
@ -7,20 +7,21 @@ using Artemis.Core;
|
|||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Debugger.Performance;
|
namespace Artemis.UI.Screens.Debugger.Performance;
|
||||||
|
|
||||||
public class PerformanceDebugViewModel : ActivatableViewModelBase
|
public partial class PerformanceDebugViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
private readonly IRenderService _renderService;
|
private readonly IRenderService _renderService;
|
||||||
private readonly IPluginManagementService _pluginManagementService;
|
private readonly IPluginManagementService _pluginManagementService;
|
||||||
private readonly DispatcherTimer _updateTimer;
|
private readonly DispatcherTimer _updateTimer;
|
||||||
private double _currentFps;
|
[Notify] private double _currentFps;
|
||||||
private string? _renderer;
|
[Notify] private string? _renderer;
|
||||||
private int _renderHeight;
|
[Notify] private int _renderHeight;
|
||||||
private int _renderWidth;
|
[Notify] private int _renderWidth;
|
||||||
|
|
||||||
public PerformanceDebugViewModel(IRenderService renderService, IPluginManagementService pluginManagementService)
|
public PerformanceDebugViewModel(IRenderService renderService, IPluginManagementService pluginManagementService)
|
||||||
{
|
{
|
||||||
@ -59,31 +60,7 @@ public class PerformanceDebugViewModel : ActivatableViewModelBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ObservableCollection<PerformanceDebugPluginViewModel> Items { get; } = new();
|
public ObservableCollection<PerformanceDebugPluginViewModel> Items { get; } = new();
|
||||||
|
|
||||||
public double CurrentFps
|
|
||||||
{
|
|
||||||
get => _currentFps;
|
|
||||||
set => RaiseAndSetIfChanged(ref _currentFps, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int RenderWidth
|
|
||||||
{
|
|
||||||
get => _renderWidth;
|
|
||||||
set => RaiseAndSetIfChanged(ref _renderWidth, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int RenderHeight
|
|
||||||
{
|
|
||||||
get => _renderHeight;
|
|
||||||
set => RaiseAndSetIfChanged(ref _renderHeight, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string? Renderer
|
|
||||||
{
|
|
||||||
get => _renderer;
|
|
||||||
set => RaiseAndSetIfChanged(ref _renderer, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleActivation()
|
private void HandleActivation()
|
||||||
{
|
{
|
||||||
Renderer = Constants.ManagedGraphicsContext != null ? Constants.ManagedGraphicsContext.GetType().Name : "Software";
|
Renderer = Constants.ManagedGraphicsContext != null ? Constants.ManagedGraphicsContext.GetType().Name : "Software";
|
||||||
|
|||||||
@ -4,21 +4,21 @@ using Artemis.Core;
|
|||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Avalonia.Media.Imaging;
|
using Avalonia.Media.Imaging;
|
||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Debugger.Render;
|
namespace Artemis.UI.Screens.Debugger.Render;
|
||||||
|
|
||||||
public class RenderDebugViewModel : ActivatableViewModelBase
|
public partial class RenderDebugViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
private readonly IRenderService _renderService;
|
private readonly IRenderService _renderService;
|
||||||
private double _currentFps;
|
|
||||||
|
|
||||||
private Bitmap? _currentFrame;
|
|
||||||
private string? _frameTargetPath;
|
private string? _frameTargetPath;
|
||||||
private string? _renderer;
|
[Notify] private double _currentFps;
|
||||||
private int _renderHeight;
|
[Notify] private Bitmap? _currentFrame;
|
||||||
private int _renderWidth;
|
[Notify] private string? _renderer;
|
||||||
|
[Notify] private int _renderHeight;
|
||||||
|
[Notify] private int _renderWidth;
|
||||||
|
|
||||||
public RenderDebugViewModel(IRenderService renderService)
|
public RenderDebugViewModel(IRenderService renderService)
|
||||||
{
|
{
|
||||||
@ -33,36 +33,6 @@ public class RenderDebugViewModel : ActivatableViewModelBase
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public Bitmap? CurrentFrame
|
|
||||||
{
|
|
||||||
get => _currentFrame;
|
|
||||||
set => RaiseAndSetIfChanged(ref _currentFrame, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public double CurrentFps
|
|
||||||
{
|
|
||||||
get => _currentFps;
|
|
||||||
set => RaiseAndSetIfChanged(ref _currentFps, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int RenderWidth
|
|
||||||
{
|
|
||||||
get => _renderWidth;
|
|
||||||
set => RaiseAndSetIfChanged(ref _renderWidth, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int RenderHeight
|
|
||||||
{
|
|
||||||
get => _renderHeight;
|
|
||||||
set => RaiseAndSetIfChanged(ref _renderHeight, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string? Renderer
|
|
||||||
{
|
|
||||||
get => _renderer;
|
|
||||||
set => RaiseAndSetIfChanged(ref _renderer, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void HandleActivation()
|
private void HandleActivation()
|
||||||
{
|
{
|
||||||
Renderer = Constants.ManagedGraphicsContext != null ? Constants.ManagedGraphicsContext.GetType().Name : "Software";
|
Renderer = Constants.ManagedGraphicsContext != null ? Constants.ManagedGraphicsContext.GetType().Name : "Software";
|
||||||
|
|||||||
@ -11,18 +11,19 @@ using Artemis.UI.Shared.Routing;
|
|||||||
using Avalonia.Controls.Documents;
|
using Avalonia.Controls.Documents;
|
||||||
using Avalonia.Media;
|
using Avalonia.Media;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
using Serilog.Formatting.Display;
|
using Serilog.Formatting.Display;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Debugger.Routing;
|
namespace Artemis.UI.Screens.Debugger.Routing;
|
||||||
|
|
||||||
public class RoutingDebugViewModel : ActivatableViewModelBase
|
public partial class RoutingDebugViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
private readonly IRouter _router;
|
private readonly IRouter _router;
|
||||||
private const int MAX_ENTRIES = 1000;
|
private const int MAX_ENTRIES = 1000;
|
||||||
private readonly MessageTemplateTextFormatter _formatter;
|
private readonly MessageTemplateTextFormatter _formatter;
|
||||||
private string? _route;
|
[Notify] private string? _route;
|
||||||
|
|
||||||
public RoutingDebugViewModel(IRouter router)
|
public RoutingDebugViewModel(IRouter router)
|
||||||
{
|
{
|
||||||
@ -49,12 +50,6 @@ public class RoutingDebugViewModel : ActivatableViewModelBase
|
|||||||
public InlineCollection Lines { get; } = new();
|
public InlineCollection Lines { get; } = new();
|
||||||
public ReactiveCommand<Unit, Unit> Navigate { get; }
|
public ReactiveCommand<Unit, Unit> Navigate { get; }
|
||||||
|
|
||||||
public string? Route
|
|
||||||
{
|
|
||||||
get => _route;
|
|
||||||
set => RaiseAndSetIfChanged(ref _route, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnLogEventAdded(object? sender, LogEventEventArgs e)
|
private void OnLogEventAdded(object? sender, LogEventEventArgs e)
|
||||||
{
|
{
|
||||||
Dispatcher.UIThread.Post(() => AddLogEvent(e.LogEvent));
|
Dispatcher.UIThread.Post(() => AddLogEvent(e.LogEvent));
|
||||||
|
|||||||
@ -0,0 +1,32 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
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:workshop="clr-namespace:Artemis.UI.Screens.Debugger.Workshop"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Artemis.UI.Screens.Debugger.Workshop.WorkshopDebugView"
|
||||||
|
x:DataType="workshop:WorkshopDebugViewModel">
|
||||||
|
<ScrollViewer Classes="with-padding">
|
||||||
|
<StackPanel>
|
||||||
|
<Label>Workshop Status</Label>
|
||||||
|
<Border Classes="card-condensed">
|
||||||
|
<SelectableTextBlock Text="{CompiledBinding WorkshopStatus}" FontFamily="{StaticResource RobotoMono}" FontSize="13" />
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Label Margin="0 10 0 0">Auth token (DO NOT SHARE)</Label>
|
||||||
|
<Border Classes="card-condensed">
|
||||||
|
<SelectableTextBlock Text="{CompiledBinding Token}" FontFamily="{StaticResource RobotoMono}" FontSize="13" TextWrapping="Wrap" />
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Label Margin="0 10 0 0">Email verified</Label>
|
||||||
|
<Border Classes="card-condensed">
|
||||||
|
<SelectableTextBlock Text="{CompiledBinding EmailVerified}" FontFamily="{StaticResource RobotoMono}" FontSize="13" />
|
||||||
|
</Border>
|
||||||
|
|
||||||
|
<Label Margin="0 10 0 0">Claims</Label>
|
||||||
|
<Border Classes="card-condensed">
|
||||||
|
<SelectableTextBlock Text="{CompiledBinding Claims}" FontFamily="{StaticResource RobotoMono}" FontSize="13" />
|
||||||
|
</Border>
|
||||||
|
</StackPanel>
|
||||||
|
</ScrollViewer>
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
using Avalonia;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Debugger.Workshop;
|
||||||
|
|
||||||
|
public partial class WorkshopDebugView : ReactiveUserControl<WorkshopDebugViewModel>
|
||||||
|
{
|
||||||
|
public WorkshopDebugView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,30 @@
|
|||||||
|
using System.Threading;
|
||||||
|
using Artemis.UI.Extensions;
|
||||||
|
using Artemis.UI.Shared;
|
||||||
|
using Artemis.WebClient.Workshop.Services;
|
||||||
|
using Newtonsoft.Json;
|
||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Debugger.Workshop;
|
||||||
|
|
||||||
|
public partial class WorkshopDebugViewModel : ActivatableViewModelBase
|
||||||
|
{
|
||||||
|
|
||||||
|
[Notify] private string? _token;
|
||||||
|
[Notify] private bool _emailVerified;
|
||||||
|
[Notify] private string? _claims;
|
||||||
|
[Notify] private IWorkshopService.WorkshopStatus? _workshopStatus;
|
||||||
|
|
||||||
|
public WorkshopDebugViewModel(IWorkshopService workshopService, IAuthenticationService authenticationService)
|
||||||
|
{
|
||||||
|
DisplayName = "Workshop";
|
||||||
|
|
||||||
|
this.WhenActivatedAsync(async _ =>
|
||||||
|
{
|
||||||
|
Token = await authenticationService.GetBearer();
|
||||||
|
EmailVerified = authenticationService.GetIsEmailVerified();
|
||||||
|
Claims = JsonConvert.SerializeObject(authenticationService.Claims, Formatting.Indented);
|
||||||
|
WorkshopStatus = await workshopService.GetWorkshopStatus(CancellationToken.None);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -6,16 +6,17 @@ using Artemis.Core;
|
|||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
using Artemis.UI.DryIoc.Factories;
|
using Artemis.UI.DryIoc.Factories;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using RGB.NET.Core;
|
using RGB.NET.Core;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Device;
|
namespace Artemis.UI.Screens.Device;
|
||||||
|
|
||||||
public class DevicePropertiesViewModel : DialogViewModelBase<object>
|
public partial class DevicePropertiesViewModel : DialogViewModelBase<object>
|
||||||
{
|
{
|
||||||
private readonly IDeviceVmFactory _deviceVmFactory;
|
private readonly IDeviceVmFactory _deviceVmFactory;
|
||||||
private ArtemisDevice _device;
|
[Notify] private ArtemisDevice _device;
|
||||||
|
|
||||||
public DevicePropertiesViewModel(ArtemisDevice device, IRenderService renderService, IDeviceService deviceService, IDeviceVmFactory deviceVmFactory)
|
public DevicePropertiesViewModel(ArtemisDevice device, IRenderService renderService, IDeviceService deviceService, IDeviceVmFactory deviceVmFactory)
|
||||||
{
|
{
|
||||||
@ -42,12 +43,6 @@ public class DevicePropertiesViewModel : DialogViewModelBase<object>
|
|||||||
ClearSelectedLeds = ReactiveCommand.Create(ExecuteClearSelectedLeds);
|
ClearSelectedLeds = ReactiveCommand.Create(ExecuteClearSelectedLeds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArtemisDevice Device
|
|
||||||
{
|
|
||||||
get => _device;
|
|
||||||
set => RaiseAndSetIfChanged(ref _device, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableCollection<ArtemisLed> SelectedLeds { get; }
|
public ObservableCollection<ArtemisLed> SelectedLeds { get; }
|
||||||
public ObservableCollection<ActivatableViewModelBase> Tabs { get; }
|
public ObservableCollection<ActivatableViewModelBase> Tabs { get; }
|
||||||
public ReactiveCommand<Unit, Unit> ClearSelectedLeds { get; }
|
public ReactiveCommand<Unit, Unit> ClearSelectedLeds { get; }
|
||||||
|
|||||||
@ -8,18 +8,19 @@ using Artemis.UI.Shared;
|
|||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using Humanizer;
|
using Humanizer;
|
||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using RGB.NET.Core;
|
using RGB.NET.Core;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Device;
|
namespace Artemis.UI.Screens.Device;
|
||||||
|
|
||||||
public class DeviceSettingsViewModel : ActivatableViewModelBase
|
public partial class DeviceSettingsViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
private readonly IDeviceService _deviceService;
|
private readonly IDeviceService _deviceService;
|
||||||
private readonly DevicesTabViewModel _devicesTabViewModel;
|
private readonly DevicesTabViewModel _devicesTabViewModel;
|
||||||
private readonly IDeviceVmFactory _deviceVmFactory;
|
private readonly IDeviceVmFactory _deviceVmFactory;
|
||||||
private readonly IWindowService _windowService;
|
private readonly IWindowService _windowService;
|
||||||
private bool _togglingDevice;
|
[Notify] private bool _togglingDevice;
|
||||||
|
|
||||||
public DeviceSettingsViewModel(ArtemisDevice device, DevicesTabViewModel devicesTabViewModel, IDeviceService deviceService, IWindowService windowService, IDeviceVmFactory deviceVmFactory)
|
public DeviceSettingsViewModel(ArtemisDevice device, DevicesTabViewModel devicesTabViewModel, IDeviceService deviceService, IWindowService windowService, IDeviceVmFactory deviceVmFactory)
|
||||||
{
|
{
|
||||||
@ -51,12 +52,6 @@ public class DeviceSettingsViewModel : ActivatableViewModelBase
|
|||||||
set => Dispatcher.UIThread.InvokeAsync(async () => await UpdateIsDeviceEnabled(value));
|
set => Dispatcher.UIThread.InvokeAsync(async () => await UpdateIsDeviceEnabled(value));
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool TogglingDevice
|
|
||||||
{
|
|
||||||
get => _togglingDevice;
|
|
||||||
set => RaiseAndSetIfChanged(ref _togglingDevice, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void IdentifyDevice()
|
public void IdentifyDevice()
|
||||||
{
|
{
|
||||||
_deviceService.IdentifyDevice(Device);
|
_deviceService.IdentifyDevice(Device);
|
||||||
|
|||||||
@ -5,9 +5,10 @@
|
|||||||
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared"
|
xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared"
|
||||||
xmlns:device="clr-namespace:Artemis.UI.Screens.Device"
|
xmlns:device="clr-namespace:Artemis.UI.Screens.Device"
|
||||||
|
xmlns:general="clr-namespace:Artemis.UI.Screens.Device.General"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="650"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="650"
|
||||||
x:Class="Artemis.UI.Screens.Device.DeviceGeneralTabView"
|
x:Class="Artemis.UI.Screens.Device.General.DeviceGeneralTabView"
|
||||||
x:DataType="device:DeviceGeneralTabViewModel">
|
x:DataType="general:DeviceGeneralTabViewModel">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<converters:SKColorToColorConverter x:Key="SKColorToColorConverter" />
|
<converters:SKColorToColorConverter x:Key="SKColorToColorConverter" />
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
@ -1,7 +1,6 @@
|
|||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Device;
|
namespace Artemis.UI.Screens.Device.General;
|
||||||
public partial class DeviceGeneralTabView : ReactiveUserControl<DeviceGeneralTabViewModel>
|
public partial class DeviceGeneralTabView : ReactiveUserControl<DeviceGeneralTabViewModel>
|
||||||
{
|
{
|
||||||
public DeviceGeneralTabView()
|
public DeviceGeneralTabView()
|
||||||
@ -1,48 +1,41 @@
|
|||||||
using Artemis.UI.Shared;
|
using System;
|
||||||
using Artemis.UI.Shared;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Reactive.Disposables;
|
using System.Reactive.Disposables;
|
||||||
using System.Text;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.UI.Screens.Device.Layout;
|
||||||
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using RGB.NET.Core;
|
using RGB.NET.Core;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Device;
|
namespace Artemis.UI.Screens.Device.General;
|
||||||
|
|
||||||
public class DeviceGeneralTabViewModel : ActivatableViewModelBase
|
public partial class DeviceGeneralTabViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
private readonly ICoreService _coreService;
|
|
||||||
private readonly IDeviceService _deviceService;
|
private readonly IDeviceService _deviceService;
|
||||||
private readonly IRenderService _renderService;
|
private readonly IRenderService _renderService;
|
||||||
private readonly IWindowService _windowService;
|
private readonly IWindowService _windowService;
|
||||||
private readonly List<DeviceCategory> _categories;
|
private readonly List<DeviceCategory> _categories;
|
||||||
|
|
||||||
private readonly float _initialBlueScale;
|
private readonly float _initialBlueScale;
|
||||||
private readonly float _initialGreenScale;
|
private readonly float _initialGreenScale;
|
||||||
private readonly float _initialRedScale;
|
private readonly float _initialRedScale;
|
||||||
|
|
||||||
private int _rotation;
|
[Notify] private int _rotation;
|
||||||
private float _scale;
|
[Notify] private float _scale;
|
||||||
private int _x;
|
[Notify] private int _x;
|
||||||
private int _y;
|
[Notify] private int _y;
|
||||||
|
[Notify] private float _redScale;
|
||||||
|
[Notify] private float _greenScale;
|
||||||
|
[Notify] private float _blueScale;
|
||||||
|
[Notify] private SKColor _currentColor;
|
||||||
|
[Notify] private bool _displayOnDevices;
|
||||||
|
|
||||||
private float _redScale;
|
public DeviceGeneralTabViewModel(ArtemisDevice device, IDeviceService deviceService, IRenderService renderService, IWindowService windowService)
|
||||||
private float _greenScale;
|
|
||||||
private float _blueScale;
|
|
||||||
private SKColor _currentColor;
|
|
||||||
private bool _displayOnDevices;
|
|
||||||
|
|
||||||
public DeviceGeneralTabViewModel(ArtemisDevice device, ICoreService coreService, IDeviceService deviceService, IRenderService renderService, IWindowService windowService)
|
|
||||||
{
|
{
|
||||||
_coreService = coreService;
|
|
||||||
_deviceService = deviceService;
|
_deviceService = deviceService;
|
||||||
_renderService = renderService;
|
_renderService = renderService;
|
||||||
_windowService = windowService;
|
_windowService = windowService;
|
||||||
@ -50,10 +43,10 @@ public class DeviceGeneralTabViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
Device = device;
|
Device = device;
|
||||||
DisplayName = "General";
|
DisplayName = "General";
|
||||||
X = (int)Device.X;
|
X = (int) Device.X;
|
||||||
Y = (int)Device.Y;
|
Y = (int) Device.Y;
|
||||||
Scale = Device.Scale;
|
Scale = Device.Scale;
|
||||||
Rotation = (int)Device.Rotation;
|
Rotation = (int) Device.Rotation;
|
||||||
RedScale = Device.RedScale * 100f;
|
RedScale = Device.RedScale * 100f;
|
||||||
GreenScale = Device.GreenScale * 100f;
|
GreenScale = Device.GreenScale * 100f;
|
||||||
BlueScale = Device.BlueScale * 100f;
|
BlueScale = Device.BlueScale * 100f;
|
||||||
@ -64,7 +57,7 @@ public class DeviceGeneralTabViewModel : ActivatableViewModelBase
|
|||||||
_initialGreenScale = Device.GreenScale;
|
_initialGreenScale = Device.GreenScale;
|
||||||
_initialBlueScale = Device.BlueScale;
|
_initialBlueScale = Device.BlueScale;
|
||||||
|
|
||||||
this.WhenAnyValue(x => x.RedScale, x => x.GreenScale, x => x.BlueScale).Subscribe(_ => ApplyScaling());
|
this.WhenAnyValue<DeviceGeneralTabViewModel, float, float, float>(x => x.RedScale, x => x.GreenScale, x => x.BlueScale).Subscribe(_ => ApplyScaling());
|
||||||
|
|
||||||
this.WhenActivated(d =>
|
this.WhenActivated(d =>
|
||||||
{
|
{
|
||||||
@ -81,31 +74,7 @@ public class DeviceGeneralTabViewModel : ActivatableViewModelBase
|
|||||||
public bool RequiresManualSetup => !Device.DeviceProvider.CanDetectPhysicalLayout || !Device.DeviceProvider.CanDetectLogicalLayout;
|
public bool RequiresManualSetup => !Device.DeviceProvider.CanDetectPhysicalLayout || !Device.DeviceProvider.CanDetectLogicalLayout;
|
||||||
|
|
||||||
public ArtemisDevice Device { get; }
|
public ArtemisDevice Device { get; }
|
||||||
|
|
||||||
public int X
|
|
||||||
{
|
|
||||||
get => _x;
|
|
||||||
set => RaiseAndSetIfChanged(ref _x, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Y
|
|
||||||
{
|
|
||||||
get => _y;
|
|
||||||
set => RaiseAndSetIfChanged(ref _y, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public float Scale
|
|
||||||
{
|
|
||||||
get => _scale;
|
|
||||||
set => RaiseAndSetIfChanged(ref _scale, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public int Rotation
|
|
||||||
{
|
|
||||||
get => _rotation;
|
|
||||||
set => RaiseAndSetIfChanged(ref _rotation, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsKeyboard => Device.DeviceType == RGBDeviceType.Keyboard;
|
public bool IsKeyboard => Device.DeviceType == RGBDeviceType.Keyboard;
|
||||||
|
|
||||||
public bool HasDeskCategory
|
public bool HasDeskCategory
|
||||||
@ -137,37 +106,7 @@ public class DeviceGeneralTabViewModel : ActivatableViewModelBase
|
|||||||
get => GetCategory(DeviceCategory.Peripherals);
|
get => GetCategory(DeviceCategory.Peripherals);
|
||||||
set => SetCategory(DeviceCategory.Peripherals, value);
|
set => SetCategory(DeviceCategory.Peripherals, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
public float RedScale
|
|
||||||
{
|
|
||||||
get => _redScale;
|
|
||||||
set => RaiseAndSetIfChanged(ref _redScale, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public float GreenScale
|
|
||||||
{
|
|
||||||
get => _greenScale;
|
|
||||||
set => RaiseAndSetIfChanged(ref _greenScale, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public float BlueScale
|
|
||||||
{
|
|
||||||
get => _blueScale;
|
|
||||||
set => RaiseAndSetIfChanged(ref _blueScale, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SKColor CurrentColor
|
|
||||||
{
|
|
||||||
get => _currentColor;
|
|
||||||
set => RaiseAndSetIfChanged(ref _currentColor, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool DisplayOnDevices
|
|
||||||
{
|
|
||||||
get => _displayOnDevices;
|
|
||||||
set => RaiseAndSetIfChanged(ref _displayOnDevices, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private bool GetCategory(DeviceCategory category)
|
private bool GetCategory(DeviceCategory category)
|
||||||
{
|
{
|
||||||
return _categories.Contains(category);
|
return _categories.Contains(category);
|
||||||
@ -189,12 +128,12 @@ public class DeviceGeneralTabViewModel : ActivatableViewModelBase
|
|||||||
return;
|
return;
|
||||||
if (!Device.DeviceProvider.CanDetectPhysicalLayout && !await DevicePhysicalLayoutDialogViewModel.SelectPhysicalLayout(_windowService, Device))
|
if (!Device.DeviceProvider.CanDetectPhysicalLayout && !await DevicePhysicalLayoutDialogViewModel.SelectPhysicalLayout(_windowService, Device))
|
||||||
return;
|
return;
|
||||||
if (!Device.DeviceProvider.CanDetectLogicalLayout && !await DeviceLogicalLayoutDialogViewModel.SelectLogicalLayout(_windowService, Device))
|
if (!Device.DeviceProvider.CanDetectLogicalLayout && !await Layout.DeviceLogicalLayoutDialogViewModel.SelectLogicalLayout(_windowService, Device))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
await Task.Delay(400);
|
await Task.Delay(400);
|
||||||
_deviceService.SaveDevice(Device);
|
_deviceService.SaveDevice(Device);
|
||||||
_deviceService.ApplyDeviceLayout(Device, Device.GetBestDeviceLayout());
|
_deviceService.LoadDeviceLayout(Device);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Apply()
|
private void Apply()
|
||||||
@ -234,7 +173,7 @@ public class DeviceGeneralTabViewModel : ActivatableViewModelBase
|
|||||||
if (!DisplayOnDevices)
|
if (!DisplayOnDevices)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
using SKPaint overlayPaint = new() { Color = CurrentColor };
|
using SKPaint overlayPaint = new() {Color = CurrentColor};
|
||||||
e.Canvas.DrawRect(0, 0, e.Canvas.LocalClipBounds.Width, e.Canvas.LocalClipBounds.Height, overlayPaint);
|
e.Canvas.DrawRect(0, 0, e.Canvas.LocalClipBounds.Width, e.Canvas.LocalClipBounds.Height, overlayPaint);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4,9 +4,10 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:device="clr-namespace:Artemis.UI.Screens.Device"
|
xmlns:device="clr-namespace:Artemis.UI.Screens.Device"
|
||||||
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||||
|
xmlns:inputMappings="clr-namespace:Artemis.UI.Screens.Device.InputMappings"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.Device.InputMappingsTabView"
|
x:Class="Artemis.UI.Screens.Device.InputMappings.InputMappingsTabView"
|
||||||
x:DataType="device:InputMappingsTabViewModel">
|
x:DataType="inputMappings:InputMappingsTabViewModel">
|
||||||
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||||
<Grid RowDefinitions="Auto,Auto,*">
|
<Grid RowDefinitions="Auto,Auto,*">
|
||||||
<StackPanel Grid.Row="0">
|
<StackPanel Grid.Row="0">
|
||||||
@ -1,7 +1,6 @@
|
|||||||
using Avalonia.Markup.Xaml;
|
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Device;
|
namespace Artemis.UI.Screens.Device.InputMappings;
|
||||||
|
|
||||||
public partial class InputMappingsTabView : ReactiveUserControl<InputMappingsTabViewModel>
|
public partial class InputMappingsTabView : ReactiveUserControl<InputMappingsTabViewModel>
|
||||||
{
|
{
|
||||||
@ -6,19 +6,19 @@ using Artemis.Core;
|
|||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
using Artemis.UI.Exceptions;
|
using Artemis.UI.Exceptions;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using HidSharp.Reports.Units;
|
using PropertyChanged.SourceGenerator;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using RGB.NET.Core;
|
using RGB.NET.Core;
|
||||||
using Unit = System.Reactive.Unit;
|
using Unit = System.Reactive.Unit;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Device;
|
namespace Artemis.UI.Screens.Device.InputMappings;
|
||||||
|
|
||||||
public class InputMappingsTabViewModel : ActivatableViewModelBase
|
public partial class InputMappingsTabViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
private readonly IInputService _inputService;
|
private readonly IInputService _inputService;
|
||||||
private readonly IDeviceService _deviceService;
|
private readonly IDeviceService _deviceService;
|
||||||
private readonly ObservableCollection<ArtemisLed> _selectedLeds;
|
private readonly ObservableCollection<ArtemisLed> _selectedLeds;
|
||||||
private ArtemisLed? _selectedLed;
|
[Notify] private ArtemisLed? _selectedLed;
|
||||||
|
|
||||||
public InputMappingsTabViewModel(ArtemisDevice device, ObservableCollection<ArtemisLed> selectedLeds, IInputService inputService, IDeviceService deviceService)
|
public InputMappingsTabViewModel(ArtemisDevice device, ObservableCollection<ArtemisLed> selectedLeds, IInputService inputService, IDeviceService deviceService)
|
||||||
{
|
{
|
||||||
@ -49,15 +49,7 @@ public class InputMappingsTabViewModel : ActivatableViewModelBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ReactiveCommand<ArtemisInputMapping, Unit> DeleteMapping { get; }
|
public ReactiveCommand<ArtemisInputMapping, Unit> DeleteMapping { get; }
|
||||||
|
|
||||||
public ArtemisDevice Device { get; }
|
public ArtemisDevice Device { get; }
|
||||||
|
|
||||||
public ArtemisLed? SelectedLed
|
|
||||||
{
|
|
||||||
get => _selectedLed;
|
|
||||||
set => RaiseAndSetIfChanged(ref _selectedLed, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ObservableCollection<ArtemisInputMapping> InputMappings { get; }
|
public ObservableCollection<ArtemisInputMapping> InputMappings { get; }
|
||||||
|
|
||||||
private void ExecuteDeleteMapping(ArtemisInputMapping inputMapping)
|
private void ExecuteDeleteMapping(ArtemisInputMapping inputMapping)
|
||||||
@ -4,10 +4,11 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||||
xmlns:device="clr-namespace:Artemis.UI.Screens.Device"
|
xmlns:layout="clr-namespace:Artemis.UI.Screens.Device.Layout"
|
||||||
|
xmlns:layoutProviders="clr-namespace:Artemis.UI.Screens.Device.Layout.LayoutProviders"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="800"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="800"
|
||||||
x:Class="Artemis.UI.Screens.Device.DeviceLayoutTabView"
|
x:Class="Artemis.UI.Screens.Device.Layout.DeviceLayoutTabView"
|
||||||
x:DataType="device:DeviceLayoutTabViewModel">
|
x:DataType="layout:DeviceLayoutTabViewModel">
|
||||||
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||||
<Border Classes="card" Margin="5">
|
<Border Classes="card" Margin="5">
|
||||||
<Grid RowDefinitions="*,Auto">
|
<Grid RowDefinitions="*,Auto">
|
||||||
@ -28,6 +29,7 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Border Classes="card-separator" />
|
<Border Classes="card-separator" />
|
||||||
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
|
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
|
||||||
<StackPanel Grid.Row="1" Grid.Column="0">
|
<StackPanel Grid.Row="1" Grid.Column="0">
|
||||||
@ -45,28 +47,43 @@
|
|||||||
</Button>
|
</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<Border Classes="card-separator" />
|
<Border Classes="card-separator" />
|
||||||
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
|
<Grid RowDefinitions="*,*,*" ColumnDefinitions="*,Auto">
|
||||||
<StackPanel Grid.Row="1" Grid.Column="0">
|
<StackPanel Grid.Row="1" Grid.Column="0">
|
||||||
<TextBlock Text="Disable default layout" />
|
<TextBlock Text="Layout provider" />
|
||||||
<TextBlock Classes="subtitle" FontSize="12" Text="With this checked, Artemis will not load a layout for this device unless you specifically provide one." />
|
<TextBlock Classes="subtitle" FontSize="12" Text="Choose between different ways to load a layout for this device." />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Grid.Row="1" Grid.Column="1" VerticalAlignment="Center">
|
<StackPanel Grid.Row="1" Grid.Column="1" VerticalAlignment="Center">
|
||||||
<CheckBox HorizontalAlignment="Right" Margin="0,0,-10,0" IsChecked="{CompiledBinding Device.DisableDefaultLayout}"/>
|
<StackPanel.Styles>
|
||||||
</StackPanel>
|
<Style Selector="ComboBox.layoutProvider /template/ ContentControl#ContentPresenter">
|
||||||
</Grid>
|
<Setter Property="ContentTemplate">
|
||||||
<Border Classes="card-separator" />
|
<Setter.Value>
|
||||||
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
|
<DataTemplate x:DataType="layoutProviders:ILayoutProviderViewModel">
|
||||||
<StackPanel Grid.Row="1" Grid.Column="0">
|
<TextBlock Text="{CompiledBinding Name}" TextWrapping="Wrap" MaxWidth="350" />
|
||||||
<TextBlock Text="Custom layout path" />
|
</DataTemplate>
|
||||||
<TextBlock Classes="subtitle" FontSize="12" Text="{CompiledBinding CustomLayoutPath, TargetNullValue=None}"/>
|
</Setter.Value>
|
||||||
</StackPanel>
|
</Setter>
|
||||||
<StackPanel Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" Orientation="Horizontal">
|
</Style>
|
||||||
<Button Content="Clear" Command="{CompiledBinding ClearCustomLayout}" IsEnabled="{CompiledBinding HasCustomLayout}" />
|
</StackPanel.Styles>
|
||||||
<!-- 5 pixels of margin between the buttons -->
|
<ComboBox Classes="layoutProvider"
|
||||||
<Button Margin="5,0,0,0" Content="Browse" Command="{CompiledBinding BrowseCustomLayout}" />
|
Width="150"
|
||||||
|
SelectedItem="{CompiledBinding SelectedLayoutProvider}"
|
||||||
|
ItemsSource="{CompiledBinding LayoutProviders}">
|
||||||
|
<ComboBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="layoutProviders:ILayoutProviderViewModel">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="{CompiledBinding Name}" TextWrapping="Wrap" MaxWidth="350" />
|
||||||
|
<TextBlock Classes="subtitle" Text="{CompiledBinding Description}" TextWrapping="Wrap" MaxWidth="350" />
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ComboBox.ItemTemplate>
|
||||||
|
</ComboBox>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
<ContentControl Content="{CompiledBinding SelectedLayoutProvider}" ClipToBounds="False" />
|
||||||
|
|
||||||
<Border Classes="card-separator" />
|
<Border Classes="card-separator" />
|
||||||
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
|
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
|
||||||
<StackPanel Grid.Row="1" Grid.Column="0">
|
<StackPanel Grid.Row="1" Grid.Column="0">
|
||||||
@ -1,11 +1,8 @@
|
|||||||
using Avalonia;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Input;
|
|
||||||
using Avalonia.Interactivity;
|
using Avalonia.Interactivity;
|
||||||
using Avalonia.Markup.Xaml;
|
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Device;
|
namespace Artemis.UI.Screens.Device.Layout;
|
||||||
|
|
||||||
public partial class DeviceLayoutTabView : ReactiveUserControl<DeviceLayoutTabViewModel>
|
public partial class DeviceLayoutTabView : ReactiveUserControl<DeviceLayoutTabViewModel>
|
||||||
{
|
{
|
||||||
@ -18,17 +15,17 @@ public partial class DeviceLayoutTabView : ReactiveUserControl<DeviceLayoutTabVi
|
|||||||
{
|
{
|
||||||
if (ViewModel?.DefaultLayoutPath is null)
|
if (ViewModel?.DefaultLayoutPath is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TopLevel.GetTopLevel(this).Clipboard.SetTextAsync(ViewModel.DefaultLayoutPath);
|
TopLevel.GetTopLevel(this)?.Clipboard?.SetTextAsync(ViewModel.DefaultLayoutPath);
|
||||||
ViewModel.ShowCopiedNotification();
|
ViewModel.ShowCopiedNotification();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ImagePathButton_OnClick(object? sender, RoutedEventArgs e)
|
private void ImagePathButton_OnClick(object? sender, RoutedEventArgs e)
|
||||||
{
|
{
|
||||||
if (ViewModel?.Device?.Layout?.Image?.LocalPath is null)
|
if (ViewModel?.Device.Layout?.Image?.LocalPath is null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
TopLevel.GetTopLevel(this).Clipboard.SetTextAsync(ViewModel.Device.Layout.Image.LocalPath);
|
TopLevel.GetTopLevel(this)?.Clipboard?.SetTextAsync(ViewModel.Device.Layout.Image.LocalPath);
|
||||||
ViewModel.ShowCopiedNotification();
|
ViewModel.ShowCopiedNotification();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,81 +1,60 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reactive.Disposables;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Xml.Serialization;
|
using System.Xml.Serialization;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Services;
|
using Artemis.UI.Screens.Device.Layout.LayoutProviders;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using Artemis.UI.Shared.Services.Builders;
|
using Artemis.UI.Shared.Services.Builders;
|
||||||
using Avalonia.Controls;
|
using PropertyChanged.SourceGenerator;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using RGB.NET.Layout;
|
using RGB.NET.Layout;
|
||||||
using SkiaSharp;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Device;
|
namespace Artemis.UI.Screens.Device.Layout;
|
||||||
|
|
||||||
public class DeviceLayoutTabViewModel : ActivatableViewModelBase
|
public partial class DeviceLayoutTabViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
|
[Notify] private ILayoutProviderViewModel? _selectedLayoutProvider;
|
||||||
|
|
||||||
private readonly IWindowService _windowService;
|
private readonly IWindowService _windowService;
|
||||||
private readonly INotificationService _notificationService;
|
private readonly INotificationService _notificationService;
|
||||||
private readonly IDeviceService _deviceService;
|
|
||||||
|
|
||||||
public DeviceLayoutTabViewModel(IWindowService windowService, INotificationService notificationService, IDeviceService deviceService, ArtemisDevice device)
|
public DeviceLayoutTabViewModel(IWindowService windowService, INotificationService notificationService, ArtemisDevice device, List<ILayoutProviderViewModel> layoutProviders)
|
||||||
{
|
{
|
||||||
_windowService = windowService;
|
_windowService = windowService;
|
||||||
_notificationService = notificationService;
|
_notificationService = notificationService;
|
||||||
_deviceService = deviceService;
|
|
||||||
|
|
||||||
Device = device;
|
Device = device;
|
||||||
DisplayName = "Layout";
|
DisplayName = "Layout";
|
||||||
DefaultLayoutPath = Device.DeviceProvider.LoadLayout(Device).FilePath;
|
DefaultLayoutPath = Device.DeviceProvider.LoadLayout(Device).FilePath;
|
||||||
|
|
||||||
this.WhenActivated(d =>
|
LayoutProviders = new ObservableCollection<ILayoutProviderViewModel>(layoutProviders);
|
||||||
|
foreach (ILayoutProviderViewModel layoutProviderViewModel in layoutProviders)
|
||||||
{
|
{
|
||||||
Device.PropertyChanged += DeviceOnPropertyChanged;
|
layoutProviderViewModel.Device = Device;
|
||||||
Disposable.Create(() => Device.PropertyChanged -= DeviceOnPropertyChanged).DisposeWith(d);
|
if (layoutProviderViewModel.Provider.IsMatch(Device))
|
||||||
|
SelectedLayoutProvider = layoutProviderViewModel;
|
||||||
|
}
|
||||||
|
|
||||||
|
// When changing device provider to one that isn't currently on the device, apply it to the device immediately
|
||||||
|
this.WhenAnyValue(vm => vm.SelectedLayoutProvider).Subscribe(l =>
|
||||||
|
{
|
||||||
|
if (l != null && !l.Provider.IsMatch(Device))
|
||||||
|
l.Apply();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArtemisDevice Device { get; }
|
public ArtemisDevice Device { get; }
|
||||||
|
public ObservableCollection<ILayoutProviderViewModel> LayoutProviders { get; set; }
|
||||||
|
|
||||||
public string DefaultLayoutPath { get; }
|
public string DefaultLayoutPath { get; }
|
||||||
|
|
||||||
public string? ImagePath => Device.Layout?.Image?.LocalPath;
|
public string? ImagePath => Device.Layout?.Image?.LocalPath;
|
||||||
|
|
||||||
public string? CustomLayoutPath => Device.CustomLayoutPath;
|
|
||||||
|
|
||||||
public bool HasCustomLayout => Device.CustomLayoutPath != null;
|
|
||||||
|
|
||||||
public void ClearCustomLayout()
|
|
||||||
{
|
|
||||||
Device.CustomLayoutPath = null;
|
|
||||||
_notificationService.CreateNotification()
|
|
||||||
.WithMessage("Cleared imported layout.")
|
|
||||||
.WithSeverity(NotificationSeverity.Informational);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task BrowseCustomLayout()
|
|
||||||
{
|
|
||||||
string[]? files = await _windowService.CreateOpenFileDialog()
|
|
||||||
.WithTitle("Select device layout file")
|
|
||||||
.HavingFilter(f => f.WithName("Layout files").WithExtension("xml"))
|
|
||||||
.ShowAsync();
|
|
||||||
|
|
||||||
if (files?.Length > 0)
|
|
||||||
{
|
|
||||||
Device.CustomLayoutPath = files[0];
|
|
||||||
_notificationService.CreateNotification()
|
|
||||||
.WithTitle("Imported layout")
|
|
||||||
.WithMessage($"File loaded from {files[0]}")
|
|
||||||
.WithSeverity(NotificationSeverity.Informational);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task ExportLayout()
|
public async Task ExportLayout()
|
||||||
{
|
{
|
||||||
string fileName = Device.DeviceProvider.GetDeviceLayoutName(Device);
|
string fileName = Device.DeviceProvider.GetDeviceLayoutName(Device);
|
||||||
@ -106,13 +85,13 @@ public class DeviceLayoutTabViewModel : ActivatableViewModelBase
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
List<LedLayout> ledLayouts = Device.Leds.Select(x => new LedLayout()
|
List<LedLayout> ledLayouts = Device.Leds.Select(x => new LedLayout
|
||||||
{
|
{
|
||||||
Id = x.RgbLed.Id.ToString(),
|
Id = x.RgbLed.Id.ToString(),
|
||||||
DescriptiveX = x.Rectangle.Left.ToString(),
|
DescriptiveX = x.Rectangle.Left.ToString(),
|
||||||
DescriptiveY = x.Rectangle.Top.ToString(),
|
DescriptiveY = x.Rectangle.Top.ToString(),
|
||||||
DescriptiveWidth = $"{x.Rectangle.Width}mm",
|
DescriptiveWidth = $"{x.Rectangle.Width}mm",
|
||||||
DescriptiveHeight = $"{x.Rectangle.Height}mm",
|
DescriptiveHeight = $"{x.Rectangle.Height}mm"
|
||||||
}).ToList();
|
}).ToList();
|
||||||
|
|
||||||
DeviceLayout emptyLayout = new()
|
DeviceLayout emptyLayout = new()
|
||||||
@ -123,7 +102,7 @@ public class DeviceLayoutTabViewModel : ActivatableViewModelBase
|
|||||||
Model = Device.RgbDevice.DeviceInfo.Model,
|
Model = Device.RgbDevice.DeviceInfo.Model,
|
||||||
Width = Device.Rectangle.Width,
|
Width = Device.Rectangle.Width,
|
||||||
Height = Device.Rectangle.Height,
|
Height = Device.Rectangle.Height,
|
||||||
InternalLeds = ledLayouts,
|
InternalLeds = ledLayouts
|
||||||
};
|
};
|
||||||
|
|
||||||
XmlSerializer serializer = new(typeof(DeviceLayout));
|
XmlSerializer serializer = new(typeof(DeviceLayout));
|
||||||
@ -145,19 +124,4 @@ public class DeviceLayoutTabViewModel : ActivatableViewModelBase
|
|||||||
.WithSeverity(NotificationSeverity.Informational)
|
.WithSeverity(NotificationSeverity.Informational)
|
||||||
.Show();
|
.Show();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DeviceOnPropertyChanged(object? sender, PropertyChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (e.PropertyName is nameof(Device.CustomLayoutPath) or nameof(Device.DisableDefaultLayout))
|
|
||||||
{
|
|
||||||
Task.Run(() =>
|
|
||||||
{
|
|
||||||
_deviceService.ApplyDeviceLayout(Device, Device.GetBestDeviceLayout());
|
|
||||||
_deviceService.SaveDevice(Device);
|
|
||||||
});
|
|
||||||
|
|
||||||
this.RaisePropertyChanged(nameof(CustomLayoutPath));
|
|
||||||
this.RaisePropertyChanged(nameof(HasCustomLayout));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
@ -2,21 +2,21 @@
|
|||||||
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:device="clr-namespace:Artemis.UI.Screens.Device"
|
|
||||||
xmlns:globalization="clr-namespace:System.Globalization;assembly=System.Runtime"
|
xmlns:globalization="clr-namespace:System.Globalization;assembly=System.Runtime"
|
||||||
|
xmlns:layout="clr-namespace:Artemis.UI.Screens.Device.Layout"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.Device.DeviceLogicalLayoutDialogView"
|
x:Class="Artemis.UI.Screens.Device.Layout.DeviceLogicalLayoutDialogView"
|
||||||
x:DataType="device:DeviceLogicalLayoutDialogViewModel">
|
x:DataType="layout:DeviceLogicalLayoutDialogViewModel">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBlock TextWrapping="Wrap">Artemis couldn't automatically determine the logical layout of your</TextBlock>
|
<TextBlock TextWrapping="Wrap">Artemis couldn't automatically determine the logical layout of your</TextBlock>
|
||||||
<TextBlock TextWrapping="Wrap" Text="{CompiledBinding Device.RgbDevice.DeviceInfo.DeviceName, Mode=OneWay}" />
|
<TextBlock TextWrapping="Wrap" Text="{CompiledBinding Device.RgbDevice.DeviceInfo.DeviceName, Mode=OneWay}" />
|
||||||
|
|
||||||
<TextBlock Margin="0 10" TextWrapping="Wrap">
|
<TextBlock Margin="0 10" TextWrapping="Wrap">
|
||||||
While not as important as the physical layout, setting the correct logical layout will allow Artemis to show the right keycaps (if a matching layout file is present)
|
While not as important as the physical layout, setting the correct logical layout will allow Artemis to show the right keycaps (if a matching layout file is present)
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
|
|
||||||
<AutoCompleteBox HorizontalAlignment="Stretch"
|
<AutoCompleteBox HorizontalAlignment="Stretch"
|
||||||
ItemsSource="{CompiledBinding Regions}"
|
ItemsSource="{CompiledBinding Regions}"
|
||||||
SelectedItem="{CompiledBinding SelectedRegion}"
|
SelectedItem="{CompiledBinding SelectedRegion}"
|
||||||
ValueMemberBinding="{CompiledBinding EnglishName, DataType=globalization:RegionInfo}"
|
ValueMemberBinding="{CompiledBinding EnglishName, DataType=globalization:RegionInfo}"
|
||||||
Watermark="Enter keyboard country name"
|
Watermark="Enter keyboard country name"
|
||||||
@ -26,12 +26,11 @@
|
|||||||
Name="RegionsAutoCompleteBox">
|
Name="RegionsAutoCompleteBox">
|
||||||
<AutoCompleteBox.ItemTemplate>
|
<AutoCompleteBox.ItemTemplate>
|
||||||
<DataTemplate DataType="{x:Type globalization:RegionInfo}">
|
<DataTemplate DataType="{x:Type globalization:RegionInfo}">
|
||||||
<StackPanel Orientation="Horizontal">
|
<TextBlock>
|
||||||
<TextBlock Text="{CompiledBinding EnglishName}"></TextBlock>
|
<Run Text="{CompiledBinding EnglishName}" />
|
||||||
<TextBlock Text=" ("/>
|
<Run Text="(" /><Run FontWeight="SemiBold" Text="{CompiledBinding TwoLetterISORegionName}" />
|
||||||
<TextBlock FontWeight="SemiBold" Text="{CompiledBinding TwoLetterISORegionName}"></TextBlock>
|
<Run Text=")" />
|
||||||
<TextBlock Text=")"/>
|
</TextBlock>
|
||||||
</StackPanel>
|
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</AutoCompleteBox.ItemTemplate>
|
</AutoCompleteBox.ItemTemplate>
|
||||||
</AutoCompleteBox>
|
</AutoCompleteBox>
|
||||||
@ -1,19 +1,17 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Globalization;
|
using System.Globalization;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Avalonia.Controls;
|
|
||||||
using Avalonia.Markup.Xaml;
|
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Device;
|
namespace Artemis.UI.Screens.Device.Layout;
|
||||||
|
|
||||||
public partial class DeviceLogicalLayoutDialogView : ReactiveUserControl<DeviceLogicalLayoutDialogViewModel>
|
public partial class DeviceLogicalLayoutDialogView : ReactiveUserControl<DeviceLogicalLayoutDialogViewModel>
|
||||||
{
|
{
|
||||||
public DeviceLogicalLayoutDialogView()
|
public DeviceLogicalLayoutDialogView()
|
||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
|
|
||||||
RegionsAutoCompleteBox.ItemFilter += SearchRegions;
|
RegionsAutoCompleteBox.ItemFilter += SearchRegions;
|
||||||
Dispatcher.UIThread.InvokeAsync(DelayedAutoFocus);
|
Dispatcher.UIThread.InvokeAsync(DelayedAutoFocus);
|
||||||
}
|
}
|
||||||
@ -25,8 +23,10 @@ public partial class DeviceLogicalLayoutDialogView : ReactiveUserControl<DeviceL
|
|||||||
RegionsAutoCompleteBox.PopulateComplete();
|
RegionsAutoCompleteBox.PopulateComplete();
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool SearchRegions(string search, object item)
|
private bool SearchRegions(string? search, object? item)
|
||||||
{
|
{
|
||||||
|
if (search == null)
|
||||||
|
return true;
|
||||||
if (item is not RegionInfo regionInfo)
|
if (item is not RegionInfo regionInfo)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -34,5 +34,4 @@ public partial class DeviceLogicalLayoutDialogView : ReactiveUserControl<DeviceL
|
|||||||
regionInfo.NativeName.Contains(search, StringComparison.OrdinalIgnoreCase) ||
|
regionInfo.NativeName.Contains(search, StringComparison.OrdinalIgnoreCase) ||
|
||||||
regionInfo.TwoLetterISORegionName.Contains(search, StringComparison.OrdinalIgnoreCase);
|
regionInfo.TwoLetterISORegionName.Contains(search, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -8,23 +8,23 @@ using Artemis.Core;
|
|||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using ContentDialogButton = Artemis.UI.Shared.Services.Builders.ContentDialogButton;
|
using ContentDialogButton = Artemis.UI.Shared.Services.Builders.ContentDialogButton;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Device;
|
namespace Artemis.UI.Screens.Device.Layout;
|
||||||
|
|
||||||
public class DeviceLogicalLayoutDialogViewModel : ContentDialogViewModelBase
|
public partial class DeviceLogicalLayoutDialogViewModel : ContentDialogViewModelBase
|
||||||
{
|
{
|
||||||
private const int LOCALE_NEUTRAL = 0x0000;
|
private const int LOCALE_NEUTRAL = 0x0000;
|
||||||
private const int LOCALE_CUSTOM_DEFAULT = 0x0c00;
|
private const int LOCALE_CUSTOM_DEFAULT = 0x0c00;
|
||||||
private const int LOCALE_INVARIANT = 0x007F;
|
private const int LOCALE_INVARIANT = 0x007F;
|
||||||
|
[Notify] private RegionInfo? _selectedRegion;
|
||||||
private RegionInfo? _selectedRegion;
|
|
||||||
|
|
||||||
public DeviceLogicalLayoutDialogViewModel(ArtemisDevice device)
|
public DeviceLogicalLayoutDialogViewModel(ArtemisDevice device)
|
||||||
{
|
{
|
||||||
Device = device;
|
Device = device;
|
||||||
ApplyLogicalLayout = ReactiveCommand.Create(ExecuteApplyLogicalLayout, this.WhenAnyValue(vm => vm.SelectedRegion).Select(r => r != null));
|
ApplyLogicalLayout = ReactiveCommand.Create(ExecuteApplyLogicalLayout, this.WhenAnyValue<DeviceLogicalLayoutDialogViewModel, RegionInfo>(vm => vm.SelectedRegion).Select(r => r != null));
|
||||||
Regions = new ObservableCollection<RegionInfo>(CultureInfo.GetCultures(CultureTypes.SpecificCultures)
|
Regions = new ObservableCollection<RegionInfo>(CultureInfo.GetCultures(CultureTypes.SpecificCultures)
|
||||||
.Where(c => c.LCID != LOCALE_INVARIANT &&
|
.Where(c => c.LCID != LOCALE_INVARIANT &&
|
||||||
c.LCID != LOCALE_NEUTRAL &&
|
c.LCID != LOCALE_NEUTRAL &&
|
||||||
@ -44,12 +44,6 @@ public class DeviceLogicalLayoutDialogViewModel : ContentDialogViewModelBase
|
|||||||
public ObservableCollection<RegionInfo> Regions { get; }
|
public ObservableCollection<RegionInfo> Regions { get; }
|
||||||
public bool Applied { get; set; }
|
public bool Applied { get; set; }
|
||||||
|
|
||||||
public RegionInfo? SelectedRegion
|
|
||||||
{
|
|
||||||
get => _selectedRegion;
|
|
||||||
set => RaiseAndSetIfChanged(ref _selectedRegion, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task<bool> SelectLogicalLayout(IWindowService windowService, ArtemisDevice device)
|
public static async Task<bool> SelectLogicalLayout(IWindowService windowService, ArtemisDevice device)
|
||||||
{
|
{
|
||||||
await windowService.CreateContentDialog()
|
await windowService.CreateContentDialog()
|
||||||
@ -2,10 +2,10 @@
|
|||||||
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:device="clr-namespace:Artemis.UI.Screens.Device"
|
xmlns:layout="clr-namespace:Artemis.UI.Screens.Device.Layout"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.Device.DevicePhysicalLayoutDialogView"
|
x:Class="Artemis.UI.Screens.Device.Layout.DevicePhysicalLayoutDialogView"
|
||||||
x:DataType="device:DevicePhysicalLayoutDialogViewModel">
|
x:DataType="layout:DevicePhysicalLayoutDialogViewModel">
|
||||||
<Grid RowDefinitions="Auto,*">
|
<Grid RowDefinitions="Auto,*">
|
||||||
<StackPanel Grid.Row="0">
|
<StackPanel Grid.Row="0">
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
@ -1,7 +1,6 @@
|
|||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.ReactiveUI;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Device;
|
namespace Artemis.UI.Screens.Device.Layout;
|
||||||
|
|
||||||
public partial class DevicePhysicalLayoutDialogView : ReactiveUserControl<DevicePhysicalLayoutDialogViewModel>
|
public partial class DevicePhysicalLayoutDialogView : ReactiveUserControl<DevicePhysicalLayoutDialogViewModel>
|
||||||
{
|
{
|
||||||
@ -9,5 +8,4 @@ public partial class DevicePhysicalLayoutDialogView : ReactiveUserControl<Device
|
|||||||
{
|
{
|
||||||
InitializeComponent();
|
InitializeComponent();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -7,7 +7,7 @@ using Artemis.UI.Shared.Services;
|
|||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Device;
|
namespace Artemis.UI.Screens.Device.Layout;
|
||||||
|
|
||||||
public class DevicePhysicalLayoutDialogViewModel : ContentDialogViewModelBase
|
public class DevicePhysicalLayoutDialogViewModel : ContentDialogViewModelBase
|
||||||
{
|
{
|
||||||
@ -0,0 +1,24 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
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:layoutProviders="clr-namespace:Artemis.UI.Screens.Device.Layout.LayoutProviders"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Artemis.UI.Screens.Device.Layout.LayoutProviders.CustomLayoutView"
|
||||||
|
x:DataType="layoutProviders:CustomLayoutViewModel"
|
||||||
|
ClipToBounds="False">
|
||||||
|
<StackPanel ClipToBounds="False">
|
||||||
|
<Border Classes="card-separator" />
|
||||||
|
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
|
||||||
|
<StackPanel Grid.Row="1" Grid.Column="0">
|
||||||
|
<TextBlock Text="Current layout" />
|
||||||
|
<TextBlock Classes="subtitle" FontSize="12" Text="{CompiledBinding Device.LayoutSelection.Parameter, TargetNullValue=None}" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" Orientation="Horizontal">
|
||||||
|
<Button Content="Clear" Command="{CompiledBinding ClearCustomLayout}" IsEnabled="{CompiledBinding !!Device.LayoutSelection.Parameter}" />
|
||||||
|
<!-- 5 pixels of margin between the buttons -->
|
||||||
|
<Button Margin="5,0,0,0" Content="Browse" Command="{CompiledBinding BrowseCustomLayout}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Device.Layout.LayoutProviders;
|
||||||
|
|
||||||
|
public partial class CustomLayoutView : UserControl
|
||||||
|
{
|
||||||
|
public CustomLayoutView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,80 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Providers;
|
||||||
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.UI.Shared;
|
||||||
|
using Artemis.UI.Shared.Services;
|
||||||
|
using Artemis.UI.Shared.Services.Builders;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Device.Layout.LayoutProviders;
|
||||||
|
|
||||||
|
public class CustomLayoutViewModel : ViewModelBase, ILayoutProviderViewModel
|
||||||
|
{
|
||||||
|
private readonly CustomPathLayoutProvider _layoutProvider;
|
||||||
|
|
||||||
|
public CustomLayoutViewModel(IWindowService windowService, INotificationService notificationService, IDeviceService deviceService, CustomPathLayoutProvider layoutProvider)
|
||||||
|
{
|
||||||
|
_layoutProvider = layoutProvider;
|
||||||
|
_windowService = windowService;
|
||||||
|
_notificationService = notificationService;
|
||||||
|
_deviceService = deviceService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Name => "Custom";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Description => "Select a layout file from a folder on your computer";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ILayoutProvider Provider => _layoutProvider;
|
||||||
|
|
||||||
|
public ArtemisDevice Device { get; set; } = null!;
|
||||||
|
|
||||||
|
private readonly IWindowService _windowService;
|
||||||
|
|
||||||
|
private readonly INotificationService _notificationService;
|
||||||
|
private readonly IDeviceService _deviceService;
|
||||||
|
|
||||||
|
public void ClearCustomLayout()
|
||||||
|
{
|
||||||
|
_layoutProvider.ConfigureDevice(Device, null);
|
||||||
|
Save();
|
||||||
|
|
||||||
|
_notificationService.CreateNotification()
|
||||||
|
.WithMessage("Cleared imported layout.")
|
||||||
|
.WithSeverity(NotificationSeverity.Informational);
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task BrowseCustomLayout()
|
||||||
|
{
|
||||||
|
string[]? files = await _windowService.CreateOpenFileDialog()
|
||||||
|
.WithTitle("Select device layout file")
|
||||||
|
.HavingFilter(f => f.WithName("Layout files").WithExtension("xml"))
|
||||||
|
.ShowAsync();
|
||||||
|
|
||||||
|
if (files?.Length > 0)
|
||||||
|
{
|
||||||
|
_layoutProvider.ConfigureDevice(Device, files[0]);
|
||||||
|
Save();
|
||||||
|
|
||||||
|
_notificationService.CreateNotification()
|
||||||
|
.WithTitle("Imported layout")
|
||||||
|
.WithMessage($"File loaded from {files[0]}")
|
||||||
|
.WithSeverity(NotificationSeverity.Informational);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Apply()
|
||||||
|
{
|
||||||
|
_layoutProvider.ConfigureDevice(Device, null);
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Save()
|
||||||
|
{
|
||||||
|
_deviceService.SaveDevice(Device);
|
||||||
|
_deviceService.LoadDeviceLayout(Device);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
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"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Artemis.UI.Screens.Device.Layout.LayoutProviders.DefaultLayoutView">
|
||||||
|
<StackPanel ClipToBounds="False">
|
||||||
|
<Border Classes="card-separator" />
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="Current layout" />
|
||||||
|
<TextBlock Classes="subtitle" FontSize="12" Text="Loading the default layout from the plugin or User Layouts folder." TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Device.Layout.LayoutProviders;
|
||||||
|
|
||||||
|
public partial class DefaultLayoutView : UserControl
|
||||||
|
{
|
||||||
|
public DefaultLayoutView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Providers;
|
||||||
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.UI.Shared;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Device.Layout.LayoutProviders;
|
||||||
|
|
||||||
|
public class DefaultLayoutViewModel : ViewModelBase, ILayoutProviderViewModel
|
||||||
|
{
|
||||||
|
private readonly DefaultLayoutProvider _layoutProvider;
|
||||||
|
private readonly IDeviceService _deviceService;
|
||||||
|
|
||||||
|
public DefaultLayoutViewModel(DefaultLayoutProvider layoutProvider, IDeviceService deviceService)
|
||||||
|
{
|
||||||
|
_layoutProvider = layoutProvider;
|
||||||
|
_deviceService = deviceService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ILayoutProvider Provider => _layoutProvider;
|
||||||
|
|
||||||
|
public ArtemisDevice Device { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Name => "Default";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Description => "Attempts to load a layout from the default paths";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Apply()
|
||||||
|
{
|
||||||
|
_layoutProvider.ConfigureDevice(Device);
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Save()
|
||||||
|
{
|
||||||
|
_deviceService.SaveDevice(Device);
|
||||||
|
_deviceService.LoadDeviceLayout(Device);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,17 @@
|
|||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Providers;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Device.Layout.LayoutProviders;
|
||||||
|
|
||||||
|
public interface ILayoutProviderViewModel
|
||||||
|
{
|
||||||
|
string Name { get; }
|
||||||
|
|
||||||
|
string Description { get; }
|
||||||
|
|
||||||
|
ILayoutProvider Provider { get; }
|
||||||
|
|
||||||
|
ArtemisDevice Device { get; set; }
|
||||||
|
|
||||||
|
void Apply();
|
||||||
|
}
|
||||||
@ -0,0 +1,14 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
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"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Artemis.UI.Screens.Device.Layout.LayoutProviders.NoneLayoutView">
|
||||||
|
<StackPanel ClipToBounds="False">
|
||||||
|
<Border Classes="card-separator" />
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="Current layout" />
|
||||||
|
<TextBlock Classes="subtitle" FontSize="12" Text="Not loading any layout, leaving LEDs to be positioned by the device provider." TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,11 @@
|
|||||||
|
using Avalonia.Controls;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Device.Layout.LayoutProviders;
|
||||||
|
|
||||||
|
public partial class NoneLayoutView : UserControl
|
||||||
|
{
|
||||||
|
public NoneLayoutView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,42 @@
|
|||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Providers;
|
||||||
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.UI.Shared;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Device.Layout.LayoutProviders;
|
||||||
|
|
||||||
|
public class NoneLayoutViewModel : ViewModelBase, ILayoutProviderViewModel
|
||||||
|
{
|
||||||
|
private readonly NoneLayoutProvider _layoutProvider;
|
||||||
|
private readonly IDeviceService _deviceService;
|
||||||
|
|
||||||
|
public NoneLayoutViewModel(NoneLayoutProvider layoutProvider, IDeviceService deviceService)
|
||||||
|
{
|
||||||
|
_layoutProvider = layoutProvider;
|
||||||
|
_deviceService = deviceService;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ILayoutProvider Provider => _layoutProvider;
|
||||||
|
|
||||||
|
public ArtemisDevice Device { get; set; } = null!;
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Name => "None";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Description => "Do not load any layout";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Apply()
|
||||||
|
{
|
||||||
|
_layoutProvider.ConfigureDevice(Device);
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Save()
|
||||||
|
{
|
||||||
|
_deviceService.SaveDevice(Device);
|
||||||
|
_deviceService.LoadDeviceLayout(Device);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,47 @@
|
|||||||
|
<UserControl xmlns="https://github.com/avaloniaui"
|
||||||
|
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:services="clr-namespace:Artemis.WebClient.Workshop.Services;assembly=Artemis.WebClient.Workshop"
|
||||||
|
xmlns:layoutProviders="clr-namespace:Artemis.UI.Screens.Device.Layout.LayoutProviders"
|
||||||
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
|
x:Class="Artemis.UI.Screens.Device.Layout.LayoutProviders.WorkshopLayoutView"
|
||||||
|
x:DataType="layoutProviders:WorkshopLayoutViewModel">
|
||||||
|
<StackPanel ClipToBounds="False">
|
||||||
|
<Border Classes="card-separator" />
|
||||||
|
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
|
||||||
|
<StackPanel Grid.Row="1" Grid.Column="0">
|
||||||
|
<TextBlock Text="Current layout" />
|
||||||
|
<TextBlock Classes="subtitle" FontSize="12" Text="Loading the layout from a workshop entry" TextWrapping="Wrap" />
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" Spacing="5">
|
||||||
|
<StackPanel.Styles>
|
||||||
|
<Style Selector="ComboBox.layoutProvider /template/ ContentControl#ContentPresenter">
|
||||||
|
<Setter Property="ContentTemplate">
|
||||||
|
<Setter.Value>
|
||||||
|
<DataTemplate x:DataType="services:InstalledEntry">
|
||||||
|
<TextBlock Text="{CompiledBinding Name}" TextWrapping="Wrap" MaxWidth="350" />
|
||||||
|
</DataTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
</StackPanel.Styles>
|
||||||
|
<ComboBox Classes="layoutProvider"
|
||||||
|
Width="350"
|
||||||
|
SelectedItem="{CompiledBinding SelectedEntry}"
|
||||||
|
ItemsSource="{CompiledBinding Entries}"
|
||||||
|
PlaceholderText="Select an installed layout">
|
||||||
|
<ComboBox.ItemTemplate>
|
||||||
|
<DataTemplate x:DataType="services:InstalledEntry">
|
||||||
|
<StackPanel>
|
||||||
|
<TextBlock Text="{CompiledBinding Name}" TextWrapping="Wrap" MaxWidth="350" />
|
||||||
|
<TextBlock Classes="subtitle" Text="{CompiledBinding Author}" TextWrapping="Wrap" MaxWidth="350" />
|
||||||
|
</StackPanel>
|
||||||
|
</DataTemplate>
|
||||||
|
</ComboBox.ItemTemplate>
|
||||||
|
</ComboBox>
|
||||||
|
<Button HorizontalAlignment="Right" Click="Button_OnClick">Browse workshop layouts</Button>
|
||||||
|
</StackPanel>
|
||||||
|
</Grid>
|
||||||
|
</StackPanel>
|
||||||
|
</UserControl>
|
||||||
@ -0,0 +1,20 @@
|
|||||||
|
using System.Threading.Tasks;
|
||||||
|
using Avalonia.Controls;
|
||||||
|
using Avalonia.Interactivity;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Device.Layout.LayoutProviders;
|
||||||
|
|
||||||
|
public partial class WorkshopLayoutView : ReactiveUserControl<WorkshopLayoutViewModel>
|
||||||
|
{
|
||||||
|
public WorkshopLayoutView()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void Button_OnClick(object? sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
if (ViewModel != null && await ViewModel.BrowseLayouts())
|
||||||
|
(VisualRoot as Window)?.Close();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,83 @@
|
|||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reactive.Disposables;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Providers;
|
||||||
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.UI.Shared;
|
||||||
|
using Artemis.UI.Shared.Routing;
|
||||||
|
using Artemis.UI.Shared.Services;
|
||||||
|
using Artemis.WebClient.Workshop;
|
||||||
|
using Artemis.WebClient.Workshop.Providers;
|
||||||
|
using Artemis.WebClient.Workshop.Services;
|
||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
|
using ReactiveUI;
|
||||||
|
|
||||||
|
namespace Artemis.UI.Screens.Device.Layout.LayoutProviders;
|
||||||
|
|
||||||
|
public partial class WorkshopLayoutViewModel : ActivatableViewModelBase, ILayoutProviderViewModel
|
||||||
|
{
|
||||||
|
[Notify] private InstalledEntry? _selectedEntry;
|
||||||
|
private readonly WorkshopLayoutProvider _layoutProvider;
|
||||||
|
private readonly IDeviceService _deviceService;
|
||||||
|
private readonly IWindowService _windowService;
|
||||||
|
private readonly IRouter _router;
|
||||||
|
|
||||||
|
public WorkshopLayoutViewModel(WorkshopLayoutProvider layoutProvider, IWorkshopService workshopService, IDeviceService deviceService, IWindowService windowService, IRouter router)
|
||||||
|
{
|
||||||
|
_layoutProvider = layoutProvider;
|
||||||
|
_deviceService = deviceService;
|
||||||
|
_windowService = windowService;
|
||||||
|
_router = router;
|
||||||
|
|
||||||
|
Entries = new ObservableCollection<InstalledEntry>(workshopService.GetInstalledEntries().Where(e => e.EntryType == EntryType.Layout));
|
||||||
|
|
||||||
|
this.WhenAnyValue(vm => vm.SelectedEntry).Subscribe(ApplyEntry);
|
||||||
|
this.WhenActivated((CompositeDisposable _) => SelectedEntry = Entries.FirstOrDefault(e => e.EntryId.ToString() == Device.LayoutSelection.Parameter));
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public ILayoutProvider Provider => _layoutProvider;
|
||||||
|
|
||||||
|
public ArtemisDevice Device { get; set; } = null!;
|
||||||
|
|
||||||
|
public ObservableCollection<InstalledEntry> Entries { get; }
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Name => "Workshop";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public string Description => "Load a layout from the workshop";
|
||||||
|
|
||||||
|
/// <inheritdoc />
|
||||||
|
public void Apply()
|
||||||
|
{
|
||||||
|
_layoutProvider.ConfigureDevice(Device, null);
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async Task<bool> BrowseLayouts()
|
||||||
|
{
|
||||||
|
if (!await _windowService.ShowConfirmContentDialog("Open workshop", "Do you want to close this window and view the workshop?"))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
await _router.Navigate("workshop/entries/layouts/1");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void ApplyEntry(InstalledEntry? entry)
|
||||||
|
{
|
||||||
|
if (entry == null || Device.LayoutSelection.Parameter == entry.EntryId.ToString())
|
||||||
|
return;
|
||||||
|
_layoutProvider.ConfigureDevice(Device, entry);
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void Save()
|
||||||
|
{
|
||||||
|
_deviceService.SaveDevice(Device);
|
||||||
|
_deviceService.LoadDeviceLayout(Device);
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -2,7 +2,7 @@
|
|||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Device;
|
namespace Artemis.UI.Screens.Device.Leds;
|
||||||
|
|
||||||
public class DeviceLedsTabLedViewModel : ViewModelBase
|
public class DeviceLedsTabLedViewModel : ViewModelBase
|
||||||
{
|
{
|
||||||
@ -5,9 +5,10 @@
|
|||||||
xmlns:device="clr-namespace:Artemis.UI.Screens.Device"
|
xmlns:device="clr-namespace:Artemis.UI.Screens.Device"
|
||||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||||
xmlns:shared="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared"
|
xmlns:shared="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared"
|
||||||
|
xmlns:leds="clr-namespace:Artemis.UI.Screens.Device.Leds"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.Device.DeviceLedsTabView"
|
x:Class="Artemis.UI.Screens.Device.Leds.DeviceLedsTabView"
|
||||||
x:DataType="device:DeviceLedsTabViewModel">
|
x:DataType="leds:DeviceLedsTabViewModel">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<converters:UriToFileNameConverter x:Key="UriToFileNameConverter" />
|
<converters:UriToFileNameConverter x:Key="UriToFileNameConverter" />
|
||||||
<converters:LedIdToStringConverter x:Key="LedIdToStringConverter" />
|
<converters:LedIdToStringConverter x:Key="LedIdToStringConverter" />
|
||||||
@ -1,7 +1,6 @@
|
|||||||
using Avalonia.Markup.Xaml;
|
|
||||||
using Avalonia.ReactiveUI;
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Device;
|
namespace Artemis.UI.Screens.Device.Leds;
|
||||||
|
|
||||||
public partial class DeviceLedsTabView : ReactiveUserControl<DeviceLedsTabViewModel>
|
public partial class DeviceLedsTabView : ReactiveUserControl<DeviceLedsTabViewModel>
|
||||||
{
|
{
|
||||||
@ -8,7 +8,7 @@ using Artemis.UI.Shared;
|
|||||||
using DynamicData.Binding;
|
using DynamicData.Binding;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Device;
|
namespace Artemis.UI.Screens.Device.Leds;
|
||||||
|
|
||||||
public class DeviceLedsTabViewModel : ActivatableViewModelBase
|
public class DeviceLedsTabViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
@ -14,20 +14,21 @@ using Artemis.UI.Shared.Services;
|
|||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using FluentAvalonia.Core;
|
using FluentAvalonia.Core;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using ContentDialogButton = Artemis.UI.Shared.Services.Builders.ContentDialogButton;
|
using ContentDialogButton = Artemis.UI.Shared.Services.Builders.ContentDialogButton;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Plugins;
|
namespace Artemis.UI.Screens.Plugins;
|
||||||
|
|
||||||
public class PluginPrerequisitesInstallDialogViewModel : ContentDialogViewModelBase
|
public partial class PluginPrerequisitesInstallDialogViewModel : ContentDialogViewModelBase
|
||||||
{
|
{
|
||||||
private PluginPrerequisiteViewModel? _activePrerequisite;
|
|
||||||
private bool _canInstall;
|
|
||||||
private bool _showFailed;
|
|
||||||
private bool _showInstall = true;
|
|
||||||
private bool _showIntro = true;
|
|
||||||
private bool _showProgress;
|
|
||||||
private CancellationTokenSource? _tokenSource;
|
private CancellationTokenSource? _tokenSource;
|
||||||
|
[Notify] private PluginPrerequisiteViewModel? _activePrerequisite;
|
||||||
|
[Notify] private bool _canInstall;
|
||||||
|
[Notify] private bool _showFailed;
|
||||||
|
[Notify] private bool _showInstall = true;
|
||||||
|
[Notify] private bool _showIntro = true;
|
||||||
|
[Notify] private bool _showProgress;
|
||||||
|
|
||||||
public PluginPrerequisitesInstallDialogViewModel(List<IPrerequisitesSubject> subjects, IPrerequisitesVmFactory prerequisitesVmFactory)
|
public PluginPrerequisitesInstallDialogViewModel(List<IPrerequisitesSubject> subjects, IPrerequisitesVmFactory prerequisitesVmFactory)
|
||||||
{
|
{
|
||||||
@ -50,43 +51,7 @@ public class PluginPrerequisitesInstallDialogViewModel : ContentDialogViewModelB
|
|||||||
|
|
||||||
public ReactiveCommand<Unit, Unit> Install { get; }
|
public ReactiveCommand<Unit, Unit> Install { get; }
|
||||||
public ObservableCollection<PluginPrerequisiteViewModel> Prerequisites { get; }
|
public ObservableCollection<PluginPrerequisiteViewModel> Prerequisites { get; }
|
||||||
|
|
||||||
public PluginPrerequisiteViewModel? ActivePrerequisite
|
|
||||||
{
|
|
||||||
get => _activePrerequisite;
|
|
||||||
set => RaiseAndSetIfChanged(ref _activePrerequisite, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ShowProgress
|
|
||||||
{
|
|
||||||
get => _showProgress;
|
|
||||||
set => RaiseAndSetIfChanged(ref _showProgress, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ShowIntro
|
|
||||||
{
|
|
||||||
get => _showIntro;
|
|
||||||
set => RaiseAndSetIfChanged(ref _showIntro, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ShowFailed
|
|
||||||
{
|
|
||||||
get => _showFailed;
|
|
||||||
set => RaiseAndSetIfChanged(ref _showFailed, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool ShowInstall
|
|
||||||
{
|
|
||||||
get => _showInstall;
|
|
||||||
set => RaiseAndSetIfChanged(ref _showInstall, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanInstall
|
|
||||||
{
|
|
||||||
get => _canInstall;
|
|
||||||
set => RaiseAndSetIfChanged(ref _canInstall, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task Show(IWindowService windowService, List<IPrerequisitesSubject> subjects)
|
public static async Task Show(IWindowService windowService, List<IPrerequisitesSubject> subjects)
|
||||||
{
|
{
|
||||||
await windowService.CreateContentDialog()
|
await windowService.CreateContentDialog()
|
||||||
|
|||||||
@ -15,19 +15,20 @@ using Artemis.UI.Shared.Services;
|
|||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using FluentAvalonia.Core;
|
using FluentAvalonia.Core;
|
||||||
using FluentAvalonia.UI.Controls;
|
using FluentAvalonia.UI.Controls;
|
||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using ContentDialogButton = Artemis.UI.Shared.Services.Builders.ContentDialogButton;
|
using ContentDialogButton = Artemis.UI.Shared.Services.Builders.ContentDialogButton;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Plugins;
|
namespace Artemis.UI.Screens.Plugins;
|
||||||
|
|
||||||
public class PluginPrerequisitesUninstallDialogViewModel : ContentDialogViewModelBase
|
public partial class PluginPrerequisitesUninstallDialogViewModel : ContentDialogViewModelBase
|
||||||
{
|
{
|
||||||
private readonly IPluginManagementService _pluginManagementService;
|
private readonly IPluginManagementService _pluginManagementService;
|
||||||
private readonly List<IPrerequisitesSubject> _subjects;
|
private readonly List<IPrerequisitesSubject> _subjects;
|
||||||
private readonly IWindowService _windowService;
|
private readonly IWindowService _windowService;
|
||||||
private PluginPrerequisiteViewModel? _activePrerequisite;
|
|
||||||
private bool _canUninstall;
|
|
||||||
private CancellationTokenSource? _tokenSource;
|
private CancellationTokenSource? _tokenSource;
|
||||||
|
[Notify] private PluginPrerequisiteViewModel? _activePrerequisite;
|
||||||
|
[Notify] private bool _canUninstall;
|
||||||
|
|
||||||
public PluginPrerequisitesUninstallDialogViewModel(List<IPrerequisitesSubject> subjects,
|
public PluginPrerequisitesUninstallDialogViewModel(List<IPrerequisitesSubject> subjects,
|
||||||
IPrerequisitesVmFactory prerequisitesVmFactory,
|
IPrerequisitesVmFactory prerequisitesVmFactory,
|
||||||
@ -59,19 +60,7 @@ public class PluginPrerequisitesUninstallDialogViewModel : ContentDialogViewMode
|
|||||||
|
|
||||||
public ReactiveCommand<Unit, Unit> Uninstall { get; }
|
public ReactiveCommand<Unit, Unit> Uninstall { get; }
|
||||||
public ObservableCollection<PluginPrerequisiteViewModel> Prerequisites { get; }
|
public ObservableCollection<PluginPrerequisiteViewModel> Prerequisites { get; }
|
||||||
|
|
||||||
public PluginPrerequisiteViewModel? ActivePrerequisite
|
|
||||||
{
|
|
||||||
get => _activePrerequisite;
|
|
||||||
set => RaiseAndSetIfChanged(ref _activePrerequisite, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanUninstall
|
|
||||||
{
|
|
||||||
get => _canUninstall;
|
|
||||||
set => RaiseAndSetIfChanged(ref _canUninstall, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static async Task Show(IWindowService windowService, List<IPrerequisitesSubject> subjects, string cancelLabel = "Cancel")
|
public static async Task Show(IWindowService windowService, List<IPrerequisitesSubject> subjects, string cancelLabel = "Cancel")
|
||||||
{
|
{
|
||||||
await windowService.CreateContentDialog()
|
await windowService.CreateContentDialog()
|
||||||
|
|||||||
@ -16,16 +16,17 @@ using Artemis.UI.Shared.Services;
|
|||||||
using Artemis.UI.Shared.Services.Builders;
|
using Artemis.UI.Shared.Services.Builders;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using Material.Icons;
|
using Material.Icons;
|
||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Plugins.Features;
|
namespace Artemis.UI.Screens.Plugins.Features;
|
||||||
|
|
||||||
public class PluginFeatureViewModel : ActivatableViewModelBase
|
public partial class PluginFeatureViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
private readonly ICoreService _coreService;
|
private readonly ICoreService _coreService;
|
||||||
private readonly IPluginManagementService _pluginManagementService;
|
private readonly IPluginManagementService _pluginManagementService;
|
||||||
private readonly IWindowService _windowService;
|
private readonly IWindowService _windowService;
|
||||||
private bool _enabling;
|
[Notify] private bool _enabling;
|
||||||
|
|
||||||
public PluginFeatureViewModel(PluginFeatureInfo pluginFeatureInfo,
|
public PluginFeatureViewModel(PluginFeatureInfo pluginFeatureInfo,
|
||||||
bool showShield,
|
bool showShield,
|
||||||
@ -73,15 +74,8 @@ public class PluginFeatureViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
public PluginFeatureInfo FeatureInfo { get; }
|
public PluginFeatureInfo FeatureInfo { get; }
|
||||||
public Exception? LoadException => FeatureInfo.LoadException;
|
public Exception? LoadException => FeatureInfo.LoadException;
|
||||||
|
|
||||||
public bool ShowShield { get; }
|
public bool ShowShield { get; }
|
||||||
|
|
||||||
public bool Enabling
|
|
||||||
{
|
|
||||||
get => _enabling;
|
|
||||||
set => RaiseAndSetIfChanged(ref _enabling, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsEnabled
|
public bool IsEnabled
|
||||||
{
|
{
|
||||||
get => FeatureInfo.AlwaysEnabled || (FeatureInfo.Instance != null && FeatureInfo.Instance.IsEnabled);
|
get => FeatureInfo.AlwaysEnabled || (FeatureInfo.Instance != null && FeatureInfo.Instance.IsEnabled);
|
||||||
|
|||||||
@ -14,21 +14,22 @@ using Artemis.UI.Shared.Services.Builders;
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
using Material.Icons;
|
using Material.Icons;
|
||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Plugins;
|
namespace Artemis.UI.Screens.Plugins;
|
||||||
|
|
||||||
public class PluginViewModel : ActivatableViewModelBase
|
public partial class PluginViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
private readonly ICoreService _coreService;
|
private readonly ICoreService _coreService;
|
||||||
private readonly INotificationService _notificationService;
|
private readonly INotificationService _notificationService;
|
||||||
private readonly IPluginManagementService _pluginManagementService;
|
private readonly IPluginManagementService _pluginManagementService;
|
||||||
private readonly IWindowService _windowService;
|
private readonly IWindowService _windowService;
|
||||||
private bool _canInstallPrerequisites;
|
|
||||||
private bool _canRemovePrerequisites;
|
|
||||||
private bool _enabling;
|
|
||||||
private Plugin _plugin;
|
|
||||||
private Window? _settingsWindow;
|
private Window? _settingsWindow;
|
||||||
|
[Notify] private bool _canInstallPrerequisites;
|
||||||
|
[Notify] private bool _canRemovePrerequisites;
|
||||||
|
[Notify] private bool _enabling;
|
||||||
|
[Notify] private Plugin _plugin;
|
||||||
|
|
||||||
public PluginViewModel(Plugin plugin,
|
public PluginViewModel(Plugin plugin,
|
||||||
ReactiveCommand<Unit, Unit>? reload,
|
ReactiveCommand<Unit, Unit>? reload,
|
||||||
@ -87,34 +88,9 @@ public class PluginViewModel : ActivatableViewModelBase
|
|||||||
public ReactiveCommand<Unit, Unit> OpenPluginDirectory { get; }
|
public ReactiveCommand<Unit, Unit> OpenPluginDirectory { get; }
|
||||||
|
|
||||||
public ObservableCollection<PluginPlatformViewModel> Platforms { get; }
|
public ObservableCollection<PluginPlatformViewModel> Platforms { get; }
|
||||||
|
|
||||||
public Plugin Plugin
|
|
||||||
{
|
|
||||||
get => _plugin;
|
|
||||||
set => RaiseAndSetIfChanged(ref _plugin, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Enabling
|
|
||||||
{
|
|
||||||
get => _enabling;
|
|
||||||
set => RaiseAndSetIfChanged(ref _enabling, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public string Type => Plugin.GetType().BaseType?.Name ?? Plugin.GetType().Name;
|
public string Type => Plugin.GetType().BaseType?.Name ?? Plugin.GetType().Name;
|
||||||
public bool IsEnabled => Plugin.IsEnabled;
|
public bool IsEnabled => Plugin.IsEnabled;
|
||||||
|
|
||||||
public bool CanInstallPrerequisites
|
|
||||||
{
|
|
||||||
get => _canInstallPrerequisites;
|
|
||||||
set => RaiseAndSetIfChanged(ref _canInstallPrerequisites, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool CanRemovePrerequisites
|
|
||||||
{
|
|
||||||
get => _canRemovePrerequisites;
|
|
||||||
set => RaiseAndSetIfChanged(ref _canRemovePrerequisites, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public async Task UpdateEnabled(bool enable)
|
public async Task UpdateEnabled(bool enable)
|
||||||
{
|
{
|
||||||
if (Enabling)
|
if (Enabling)
|
||||||
|
|||||||
@ -6,21 +6,20 @@ using System.Threading;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Plugins.Prerequisites;
|
namespace Artemis.UI.Screens.Plugins.Prerequisites;
|
||||||
|
|
||||||
public class PluginPrerequisiteViewModel : ActivatableViewModelBase
|
public partial class PluginPrerequisiteViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
private readonly ObservableAsPropertyHelper<int> _activeStepNumber;
|
private readonly ObservableAsPropertyHelper<int> _activeStepNumber;
|
||||||
private readonly ObservableAsPropertyHelper<bool> _busy;
|
private readonly ObservableAsPropertyHelper<bool> _busy;
|
||||||
private readonly bool _uninstall;
|
private readonly bool _uninstall;
|
||||||
|
[Notify] private PluginPrerequisiteActionViewModel? _activeAction;
|
||||||
private PluginPrerequisiteActionViewModel? _activeAction;
|
[Notify] private bool _installing;
|
||||||
|
[Notify] private bool _isMet;
|
||||||
private bool _installing;
|
[Notify] private bool _uninstalling;
|
||||||
private bool _isMet;
|
|
||||||
private bool _uninstalling;
|
|
||||||
|
|
||||||
public PluginPrerequisiteViewModel(PluginPrerequisite pluginPrerequisite, bool uninstall)
|
public PluginPrerequisiteViewModel(PluginPrerequisite pluginPrerequisite, bool uninstall)
|
||||||
{
|
{
|
||||||
@ -45,33 +44,7 @@ public class PluginPrerequisiteViewModel : ActivatableViewModelBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
public ObservableCollection<PluginPrerequisiteActionViewModel> Actions { get; }
|
public ObservableCollection<PluginPrerequisiteActionViewModel> Actions { get; }
|
||||||
|
|
||||||
public PluginPrerequisiteActionViewModel? ActiveAction
|
|
||||||
{
|
|
||||||
get => _activeAction;
|
|
||||||
set => RaiseAndSetIfChanged(ref _activeAction, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public PluginPrerequisite PluginPrerequisite { get; }
|
public PluginPrerequisite PluginPrerequisite { get; }
|
||||||
|
|
||||||
public bool Installing
|
|
||||||
{
|
|
||||||
get => _installing;
|
|
||||||
set => RaiseAndSetIfChanged(ref _installing, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Uninstalling
|
|
||||||
{
|
|
||||||
get => _uninstalling;
|
|
||||||
set => RaiseAndSetIfChanged(ref _uninstalling, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool IsMet
|
|
||||||
{
|
|
||||||
get => _isMet;
|
|
||||||
set => RaiseAndSetIfChanged(ref _isMet, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool Busy => _busy.Value;
|
public bool Busy => _busy.Value;
|
||||||
public int ActiveStepNumber => _activeStepNumber.Value;
|
public int ActiveStepNumber => _activeStepNumber.Value;
|
||||||
|
|
||||||
|
|||||||
@ -15,11 +15,12 @@ using Artemis.UI.Shared.Routing;
|
|||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using Artemis.UI.Shared.Services.ProfileEditor;
|
using Artemis.UI.Shared.Services.ProfileEditor;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.MenuBar;
|
namespace Artemis.UI.Screens.ProfileEditor.MenuBar;
|
||||||
|
|
||||||
public class MenuBarViewModel : ActivatableViewModelBase
|
public partial class MenuBarViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
private readonly IRouter _router;
|
private readonly IRouter _router;
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
@ -29,12 +30,12 @@ public class MenuBarViewModel : ActivatableViewModelBase
|
|||||||
private ObservableAsPropertyHelper<bool>? _focusFolder;
|
private ObservableAsPropertyHelper<bool>? _focusFolder;
|
||||||
private ObservableAsPropertyHelper<bool>? _focusNone;
|
private ObservableAsPropertyHelper<bool>? _focusNone;
|
||||||
private ObservableAsPropertyHelper<bool>? _focusSelection;
|
private ObservableAsPropertyHelper<bool>? _focusSelection;
|
||||||
private ProfileEditorHistory? _history;
|
|
||||||
private ObservableAsPropertyHelper<bool>? _isSuspended;
|
private ObservableAsPropertyHelper<bool>? _isSuspended;
|
||||||
private ObservableAsPropertyHelper<bool>? _keyBindingsEnabled;
|
private ObservableAsPropertyHelper<bool>? _keyBindingsEnabled;
|
||||||
private ObservableAsPropertyHelper<ProfileConfiguration?>? _profileConfiguration;
|
private ObservableAsPropertyHelper<ProfileConfiguration?>? _profileConfiguration;
|
||||||
private ObservableAsPropertyHelper<RenderProfileElement?>? _profileElement;
|
private ObservableAsPropertyHelper<RenderProfileElement?>? _profileElement;
|
||||||
private ObservableAsPropertyHelper<bool>? _suspendedEditing;
|
private ObservableAsPropertyHelper<bool>? _suspendedEditing;
|
||||||
|
[Notify] private ProfileEditorHistory? _history;
|
||||||
|
|
||||||
public MenuBarViewModel(IRouter router, IProfileEditorService profileEditorService, IProfileService profileService, ISettingsService settingsService, IWindowService windowService)
|
public MenuBarViewModel(IRouter router, IProfileEditorService profileEditorService, IProfileService profileService, ISettingsService settingsService, IWindowService windowService)
|
||||||
{
|
{
|
||||||
@ -108,12 +109,6 @@ public class MenuBarViewModel : ActivatableViewModelBase
|
|||||||
public PluginSetting<bool> AlwaysApplyDataBindings => _settingsService.GetSetting("ProfileEditor.AlwaysApplyDataBindings", false);
|
public PluginSetting<bool> AlwaysApplyDataBindings => _settingsService.GetSetting("ProfileEditor.AlwaysApplyDataBindings", false);
|
||||||
public PluginSetting<ProfileEditorFocusMode> FocusMode => _settingsService.GetSetting("ProfileEditor.FocusMode", ProfileEditorFocusMode.Folder);
|
public PluginSetting<ProfileEditorFocusMode> FocusMode => _settingsService.GetSetting("ProfileEditor.FocusMode", ProfileEditorFocusMode.Folder);
|
||||||
|
|
||||||
public ProfileEditorHistory? History
|
|
||||||
{
|
|
||||||
get => _history;
|
|
||||||
set => RaiseAndSetIfChanged(ref _history, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void ExecuteAddFolder()
|
private void ExecuteAddFolder()
|
||||||
{
|
{
|
||||||
if (ProfileConfiguration?.Profile == null)
|
if (ProfileConfiguration?.Profile == null)
|
||||||
|
|||||||
@ -8,11 +8,12 @@ using Artemis.Core.Services;
|
|||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
using Artemis.UI.Shared.Services.ProfileEditor;
|
using Artemis.UI.Shared.Services.ProfileEditor;
|
||||||
using Avalonia.Threading;
|
using Avalonia.Threading;
|
||||||
|
using PropertyChanged.SourceGenerator;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.ProfileEditor.Playback;
|
namespace Artemis.UI.Screens.ProfileEditor.Playback;
|
||||||
|
|
||||||
public class PlaybackViewModel : ActivatableViewModelBase
|
public partial class PlaybackViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
private readonly IProfileEditorService _profileEditorService;
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private readonly ISettingsService _settingsService;
|
private readonly ISettingsService _settingsService;
|
||||||
@ -22,9 +23,9 @@ public class PlaybackViewModel : ActivatableViewModelBase
|
|||||||
private DateTime _lastUpdate;
|
private DateTime _lastUpdate;
|
||||||
private ObservableAsPropertyHelper<bool>? _playing;
|
private ObservableAsPropertyHelper<bool>? _playing;
|
||||||
private RenderProfileElement? _profileElement;
|
private RenderProfileElement? _profileElement;
|
||||||
private bool _repeating;
|
[Notify] private bool _repeating;
|
||||||
private bool _repeatSegment;
|
[Notify] private bool _repeatSegment;
|
||||||
private bool _repeatTimeline;
|
[Notify] private bool _repeatTimeline;
|
||||||
|
|
||||||
public PlaybackViewModel(IProfileEditorService profileEditorService, ISettingsService settingsService)
|
public PlaybackViewModel(IProfileEditorService profileEditorService, ISettingsService settingsService)
|
||||||
{
|
{
|
||||||
@ -84,24 +85,6 @@ public class PlaybackViewModel : ActivatableViewModelBase
|
|||||||
public bool Playing => _playing?.Value ?? false;
|
public bool Playing => _playing?.Value ?? false;
|
||||||
public bool KeyBindingsEnabled => _keyBindingsEnabled?.Value ?? false;
|
public bool KeyBindingsEnabled => _keyBindingsEnabled?.Value ?? false;
|
||||||
|
|
||||||
public bool Repeating
|
|
||||||
{
|
|
||||||
get => _repeating;
|
|
||||||
set => RaiseAndSetIfChanged(ref _repeating, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool RepeatTimeline
|
|
||||||
{
|
|
||||||
get => _repeatTimeline;
|
|
||||||
set => RaiseAndSetIfChanged(ref _repeatTimeline, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool RepeatSegment
|
|
||||||
{
|
|
||||||
get => _repeatSegment;
|
|
||||||
set => RaiseAndSetIfChanged(ref _repeatSegment, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ReactiveCommand<Unit, Unit> PlayFromStart { get; }
|
public ReactiveCommand<Unit, Unit> PlayFromStart { get; }
|
||||||
public ReactiveCommand<Unit, Unit> TogglePlay { get; }
|
public ReactiveCommand<Unit, Unit> TogglePlay { get; }
|
||||||
public ReactiveCommand<Unit, Unit> GoToStart { get; }
|
public ReactiveCommand<Unit, Unit> GoToStart { get; }
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user