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
fbf04b53db
@ -15,7 +15,7 @@ Artemis 1 is no longer supported and Artemis 2 is in active development. This en
|
||||
**Pre-release download**: https://github.com/SpoinkyNL/Artemis/releases (pre-release means your profiles may break at any given time!)
|
||||
**Plugin documentation**: https://artemis-rgb.com/docs/
|
||||
|
||||
**Please note that even though we have plugins for each brand supported by RGB.NET, they have not been thoroughly tested. If you run into any issues please let us know on Discord.**
|
||||
**Please note that even though we have plugins for each brand supported by RGB.NET, they have not been thoroughly tested due to a lack of hardware. If you run into any issues please let us know on Discord.**
|
||||
A full list of supported devices can be found on the wiki [here](https://wiki.artemis-rgb.com/en/guides/user/devices).
|
||||
|
||||
#### Want to build? Follow these instructions
|
||||
|
||||
@ -9,6 +9,7 @@
|
||||
RegisterDataBindingProperty(() => CurrentValue.End, value => CurrentValue.End = value, new FloatDataBindingConverter<FloatRange>(), "End");
|
||||
|
||||
CurrentValueSet += OnCurrentValueSet;
|
||||
DefaultValue = new FloatRange();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -25,7 +26,7 @@
|
||||
private void OnCurrentValueSet(object? sender, LayerPropertyEventArgs e)
|
||||
{
|
||||
// Don't allow the int range to be null
|
||||
BaseValue ??= DefaultValue ?? new FloatRange(0, 0);
|
||||
BaseValue ??= DefaultValue ?? new FloatRange();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,6 +9,7 @@
|
||||
RegisterDataBindingProperty(() => CurrentValue.End, value => CurrentValue.End = value, new IntDataBindingConverter<IntRange>(), "End");
|
||||
|
||||
CurrentValueSet += OnCurrentValueSet;
|
||||
DefaultValue = new IntRange();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -25,7 +26,7 @@
|
||||
private void OnCurrentValueSet(object? sender, LayerPropertyEventArgs e)
|
||||
{
|
||||
// Don't allow the int range to be null
|
||||
BaseValue ??= DefaultValue ?? new IntRange(0, 0);
|
||||
BaseValue ??= DefaultValue ?? new IntRange();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,6 +9,14 @@ namespace Artemis.Core
|
||||
{
|
||||
private readonly Random _rand;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="FloatRange" /> class
|
||||
/// </summary>
|
||||
public FloatRange()
|
||||
{
|
||||
_rand = new Random();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="FloatRange" /> class
|
||||
/// </summary>
|
||||
|
||||
@ -9,6 +9,14 @@ namespace Artemis.Core
|
||||
{
|
||||
private readonly Random _rand;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="IntRange" /> class
|
||||
/// </summary>
|
||||
public IntRange()
|
||||
{
|
||||
_rand = new Random();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="IntRange" /> class
|
||||
/// </summary>
|
||||
|
||||
@ -34,7 +34,15 @@ namespace Artemis.Core
|
||||
CurrentValue = default!;
|
||||
DefaultValue = default!;
|
||||
|
||||
_baseValue = default!;
|
||||
// We'll try our best...
|
||||
// TODO: Consider alternatives
|
||||
if (typeof(T).IsValueType)
|
||||
_baseValue = default!;
|
||||
else if (typeof(T).GetConstructor(Type.EmptyTypes) != null)
|
||||
_baseValue = Activator.CreateInstance<T>();
|
||||
else
|
||||
_baseValue = default!;
|
||||
|
||||
_keyframes = new List<LayerPropertyKeyframe<T>>();
|
||||
}
|
||||
|
||||
|
||||
@ -35,10 +35,9 @@ namespace Artemis.Core
|
||||
IsEnabled = true;
|
||||
|
||||
InputIdentifiers = new List<ArtemisDeviceInputIdentifier>();
|
||||
InputMappings = new Dictionary<ArtemisLed, ArtemisLed>();
|
||||
|
||||
Leds = rgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly();
|
||||
LedIds = new ReadOnlyDictionary<LedId, ArtemisLed>(Leds.ToDictionary(l => l.RgbLed.Id, l => l));
|
||||
|
||||
UpdateLeds();
|
||||
ApplyKeyboardLayout();
|
||||
ApplyToEntity();
|
||||
CalculateRenderProperties();
|
||||
@ -52,12 +51,12 @@ namespace Artemis.Core
|
||||
DeviceProvider = deviceProvider;
|
||||
|
||||
InputIdentifiers = new List<ArtemisDeviceInputIdentifier>();
|
||||
InputMappings = new Dictionary<ArtemisLed, ArtemisLed>();
|
||||
|
||||
foreach (DeviceInputIdentifierEntity identifierEntity in DeviceEntity.InputIdentifiers)
|
||||
InputIdentifiers.Add(new ArtemisDeviceInputIdentifier(identifierEntity.InputProvider, identifierEntity.Identifier));
|
||||
|
||||
Leds = rgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly();
|
||||
LedIds = new ReadOnlyDictionary<LedId, ArtemisLed>(Leds.ToDictionary(l => l.RgbLed.Id, l => l));
|
||||
|
||||
UpdateLeds();
|
||||
ApplyKeyboardLayout();
|
||||
}
|
||||
|
||||
@ -110,6 +109,8 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public List<ArtemisDeviceInputIdentifier> InputIdentifiers { get; }
|
||||
|
||||
public Dictionary<ArtemisLed, ArtemisLed> InputMappings { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the X-position of the device
|
||||
/// </summary>
|
||||
@ -287,20 +288,27 @@ namespace Artemis.Core
|
||||
/// Attempts to retrieve the <see cref="ArtemisLed" /> that corresponds the provided RGB.NET <see cref="Led" />
|
||||
/// </summary>
|
||||
/// <param name="led">The RGB.NET <see cref="Led" /> to find the corresponding <see cref="ArtemisLed" /> for </param>
|
||||
/// <param name="applyInputMapping">If <see langword="true"/>, LEDs mapped to different LEDs <see cref="InputMappings"/> are taken into consideration</param>
|
||||
/// <returns>If found, the corresponding <see cref="ArtemisLed" />; otherwise <see langword="null" />.</returns>
|
||||
public ArtemisLed? GetLed(Led led)
|
||||
public ArtemisLed? GetLed(Led led, bool applyInputMapping)
|
||||
{
|
||||
return GetLed(led.Id);
|
||||
return GetLed(led.Id, applyInputMapping);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to retrieve the <see cref="ArtemisLed" /> that corresponds the provided RGB.NET <see cref="LedId" />
|
||||
/// </summary>
|
||||
/// <param name="ledId">The RGB.NET <see cref="LedId" /> to find the corresponding <see cref="ArtemisLed" /> for </param>
|
||||
/// <param name="applyInputMapping">If <see langword="true"/>, LEDs mapped to different LEDs <see cref="InputMappings"/> are taken into consideration</param>
|
||||
/// <returns>If found, the corresponding <see cref="ArtemisLed" />; otherwise <see langword="null" />.</returns>
|
||||
public ArtemisLed? GetLed(LedId ledId)
|
||||
public ArtemisLed? GetLed(LedId ledId, bool applyInputMapping)
|
||||
{
|
||||
LedIds.TryGetValue(ledId, out ArtemisLed? artemisLed);
|
||||
if (artemisLed == null)
|
||||
return null;
|
||||
|
||||
if (applyInputMapping && InputMappings.TryGetValue(artemisLed, out ArtemisLed? mappedLed))
|
||||
return mappedLed;
|
||||
return artemisLed;
|
||||
}
|
||||
|
||||
@ -339,8 +347,7 @@ namespace Artemis.Core
|
||||
if (layout.IsValid)
|
||||
layout.RgbLayout!.ApplyTo(RgbDevice, createMissingLeds, removeExcessiveLeds);
|
||||
|
||||
Leds = RgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly();
|
||||
LedIds = new ReadOnlyDictionary<LedId, ArtemisLed>(Leds.ToDictionary(l => l.RgbLed.Id, l => l));
|
||||
UpdateLeds();
|
||||
|
||||
Layout = layout;
|
||||
Layout.ApplyDevice(this);
|
||||
@ -348,6 +355,21 @@ namespace Artemis.Core
|
||||
OnDeviceUpdated();
|
||||
}
|
||||
|
||||
private void UpdateLeds()
|
||||
{
|
||||
Leds = RgbDevice.Select(l => new ArtemisLed(l, this)).ToList().AsReadOnly();
|
||||
LedIds = new ReadOnlyDictionary<LedId, ArtemisLed>(Leds.ToDictionary(l => l.RgbLed.Id, l => l));
|
||||
|
||||
InputMappings.Clear();
|
||||
foreach (InputMappingEntity deviceEntityInputMapping in DeviceEntity.InputMappings)
|
||||
{
|
||||
ArtemisLed? original = Leds.FirstOrDefault(l => l.RgbLed.Id == (LedId) deviceEntityInputMapping.OriginalLedId);
|
||||
ArtemisLed? mapped = Leds.FirstOrDefault(l => l.RgbLed.Id == (LedId) deviceEntityInputMapping.MappedLedId);
|
||||
if (original != null && mapped != null)
|
||||
InputMappings.Add(original, mapped);
|
||||
}
|
||||
}
|
||||
|
||||
internal void ApplyToEntity()
|
||||
{
|
||||
// Other properties are computed
|
||||
@ -362,6 +384,10 @@ namespace Artemis.Core
|
||||
Identifier = identifier.Identifier
|
||||
});
|
||||
}
|
||||
|
||||
DeviceEntity.InputMappings.Clear();
|
||||
foreach (var (original, mapped) in InputMappings)
|
||||
DeviceEntity.InputMappings.Add(new InputMappingEntity {OriginalLedId = (int) original.RgbLed.Id, MappedLedId = (int) mapped.RgbLed.Id});
|
||||
}
|
||||
|
||||
internal void ApplyToRgbDevice()
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using Artemis.Core.Services;
|
||||
using RGB.NET.Core;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
@ -12,7 +13,7 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
/// <param name="inputProvider">The full type and namespace of the <see cref="Services.InputProvider" /> this identifier is used by</param>
|
||||
/// <param name="identifier">A value used to identify the device</param>
|
||||
public ArtemisDeviceInputIdentifier(string inputProvider, object identifier)
|
||||
internal ArtemisDeviceInputIdentifier(string inputProvider, object identifier)
|
||||
{
|
||||
InputProvider = inputProvider;
|
||||
Identifier = identifier;
|
||||
@ -28,4 +29,16 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public object Identifier { get; set; }
|
||||
}
|
||||
|
||||
public class ArtemisDeviceInputMapping
|
||||
{
|
||||
public ArtemisLed OriginalLed { get; }
|
||||
public ArtemisLed MappedLed { get; }
|
||||
|
||||
internal ArtemisDeviceInputMapping(ArtemisLed originalLed, ArtemisLed mappedLed)
|
||||
{
|
||||
OriginalLed = originalLed;
|
||||
MappedLed = mappedLed;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3,9 +3,15 @@ using RGB.NET.Core;
|
||||
|
||||
namespace Artemis.Core.Services
|
||||
{
|
||||
internal static class InputKeyUtilities
|
||||
/// <summary>
|
||||
/// Utilities for mapping keys and buttons to LEDs
|
||||
/// </summary>
|
||||
public static class InputKeyUtilities
|
||||
{
|
||||
internal static readonly Dictionary<KeyboardKey, LedId> KeyboardKeyLedIdMap = new()
|
||||
/// <summary>
|
||||
/// A dictionary of mappings between <see cref="KeyboardKey" /> and <see cref="LedId" />
|
||||
/// </summary>
|
||||
public static readonly Dictionary<KeyboardKey, LedId> KeyboardKeyLedIdMap = new()
|
||||
{
|
||||
{KeyboardKey.None, LedId.Keyboard_Custom1},
|
||||
{KeyboardKey.Cancel, LedId.Keyboard_Custom2},
|
||||
@ -182,7 +188,10 @@ namespace Artemis.Core.Services
|
||||
{KeyboardKey.NumPadEnter, LedId.Keyboard_NumEnter}
|
||||
};
|
||||
|
||||
internal static readonly Dictionary<MouseButton, LedId> MouseButtonLedIdMap = new()
|
||||
/// <summary>
|
||||
/// A dictionary of mappings between <see cref="MouseButton" /> and <see cref="LedId" />
|
||||
/// </summary>
|
||||
public static readonly Dictionary<MouseButton, LedId> MouseButtonLedIdMap = new()
|
||||
{
|
||||
{MouseButton.Left, LedId.Mouse1},
|
||||
{MouseButton.Middle, LedId.Mouse2},
|
||||
|
||||
@ -201,7 +201,7 @@ namespace Artemis.Core.Services
|
||||
bool foundLedId = InputKeyUtilities.KeyboardKeyLedIdMap.TryGetValue(e.Key, out LedId ledId);
|
||||
ArtemisLed? led = null;
|
||||
if (foundLedId && e.Device != null)
|
||||
led = e.Device.GetLed(ledId);
|
||||
led = e.Device.GetLed(ledId, true);
|
||||
|
||||
// Create the UpDown event args because it can be used for every event
|
||||
ArtemisKeyboardKeyUpDownEventArgs eventArgs = new(e.Device, led, e.Key, keyboardModifierKey, e.IsDown);
|
||||
|
||||
@ -7,6 +7,7 @@ namespace Artemis.Storage.Entities.Surface
|
||||
public DeviceEntity()
|
||||
{
|
||||
InputIdentifiers = new List<DeviceInputIdentifierEntity>();
|
||||
InputMappings = new List<InputMappingEntity>();
|
||||
}
|
||||
|
||||
public string Id { get; set; }
|
||||
@ -25,9 +26,16 @@ namespace Artemis.Storage.Entities.Surface
|
||||
public string CustomLayoutPath { get; set; }
|
||||
|
||||
public List<DeviceInputIdentifierEntity> InputIdentifiers { get; set; }
|
||||
public List<InputMappingEntity> InputMappings { get; set; }
|
||||
|
||||
}
|
||||
|
||||
public class InputMappingEntity
|
||||
{
|
||||
public int OriginalLedId { get; set; }
|
||||
public int MappedLedId { get; set; }
|
||||
}
|
||||
|
||||
public class DeviceInputIdentifierEntity
|
||||
{
|
||||
public string InputProvider { get; set; }
|
||||
|
||||
@ -6,6 +6,18 @@ namespace Artemis.UI.Shared.LayerBrushes
|
||||
/// <inheritdoc />
|
||||
public class LayerBrushConfigurationDialog<T> : LayerBrushConfigurationDialog where T : BrushConfigurationViewModel
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public LayerBrushConfigurationDialog()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public LayerBrushConfigurationDialog(int dialogWidth, int dialogHeight)
|
||||
{
|
||||
DialogWidth = dialogWidth;
|
||||
DialogHeight = dialogHeight;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Type Type => typeof(T);
|
||||
}
|
||||
@ -15,6 +27,16 @@ namespace Artemis.UI.Shared.LayerBrushes
|
||||
/// </summary>
|
||||
public abstract class LayerBrushConfigurationDialog : ILayerBrushConfigurationDialog
|
||||
{
|
||||
/// <summary>
|
||||
/// The default width of the dialog
|
||||
/// </summary>
|
||||
public int DialogWidth { get; set; } = 800;
|
||||
|
||||
/// <summary>
|
||||
/// The default height of the dialog
|
||||
/// </summary>
|
||||
public int DialogHeight { get; set; } = 800;
|
||||
|
||||
/// <summary>
|
||||
/// The type of view model the tab contains
|
||||
/// </summary>
|
||||
|
||||
@ -6,6 +6,19 @@ namespace Artemis.UI.Shared.LayerEffects
|
||||
/// <inheritdoc />
|
||||
public class LayerEffectConfigurationDialog<T> : LayerEffectConfigurationDialog where T : EffectConfigurationViewModel
|
||||
{
|
||||
|
||||
/// <inheritdoc />
|
||||
public LayerEffectConfigurationDialog()
|
||||
{
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public LayerEffectConfigurationDialog(int dialogWidth, int dialogHeight)
|
||||
{
|
||||
DialogWidth = dialogWidth;
|
||||
DialogHeight = dialogHeight;
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override Type Type => typeof(T);
|
||||
}
|
||||
@ -15,11 +28,15 @@ namespace Artemis.UI.Shared.LayerEffects
|
||||
/// </summary>
|
||||
public abstract class LayerEffectConfigurationDialog : ILayerEffectConfigurationDialog
|
||||
{
|
||||
// TODO: See if this is still in use
|
||||
/// <summary>
|
||||
/// The layer effect this dialog belongs to
|
||||
/// The default width of the dialog
|
||||
/// </summary>
|
||||
public BaseLayerEffect? LayerEffect { get; set; }
|
||||
public int DialogWidth { get; set; } = 800;
|
||||
|
||||
/// <summary>
|
||||
/// The default height of the dialog
|
||||
/// </summary>
|
||||
public int DialogHeight { get; set; } = 800;
|
||||
|
||||
/// <summary>
|
||||
/// The type of view model the tab contains
|
||||
|
||||
@ -49,6 +49,7 @@ namespace Artemis.UI.Ninject.Factories
|
||||
DevicePropertiesTabViewModel DevicePropertiesTabViewModel(ArtemisDevice device);
|
||||
DeviceInfoTabViewModel DeviceInfoTabViewModel(ArtemisDevice device);
|
||||
DeviceLedsTabViewModel DeviceLedsTabViewModel(ArtemisDevice device);
|
||||
InputMappingsTabViewModel InputMappingsTabViewModel(ArtemisDevice device);
|
||||
}
|
||||
|
||||
public interface IProfileTreeVmFactory : IVmFactory
|
||||
|
||||
@ -75,8 +75,11 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
||||
ConstructorArgument argument = new(brushParameter.Name, layerBrush);
|
||||
BrushConfigurationViewModel viewModel = (BrushConfigurationViewModel) layerBrush.Descriptor.Provider.Plugin.Kernel.Get(configurationViewModel.Type, argument);
|
||||
|
||||
_layerBrushSettingsWindowVm = new LayerBrushSettingsWindowViewModel(viewModel);
|
||||
_layerBrushSettingsWindowVm = new LayerBrushSettingsWindowViewModel(viewModel, configurationViewModel);
|
||||
_windowManager.ShowDialog(_layerBrushSettingsWindowVm);
|
||||
|
||||
// Save changes after the dialog closes
|
||||
_profileEditorService.UpdateSelectedProfile();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -102,8 +105,11 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree
|
||||
ConstructorArgument argument = new(effectParameter.Name, layerEffect);
|
||||
EffectConfigurationViewModel viewModel = (EffectConfigurationViewModel) layerEffect.Descriptor.Provider.Plugin.Kernel.Get(configurationViewModel.Type, argument);
|
||||
|
||||
_layerEffectSettingsWindowVm = new LayerEffectSettingsWindowViewModel(viewModel);
|
||||
_layerEffectSettingsWindowVm = new LayerEffectSettingsWindowViewModel(viewModel, configurationViewModel);
|
||||
_windowManager.ShowDialog(_layerEffectSettingsWindowVm);
|
||||
|
||||
// Save changes after the dialog closes
|
||||
_profileEditorService.UpdateSelectedProfile();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
|
||||
@ -12,8 +12,8 @@
|
||||
Background="{DynamicResource MaterialDesignPaper}"
|
||||
FontFamily="pack://application:,,,/MaterialDesignThemes.Wpf;component/Resources/Roboto/#Roboto"
|
||||
UseLayoutRounding="True"
|
||||
Width="800"
|
||||
Height="800"
|
||||
Width="800"
|
||||
d:DesignHeight="800"
|
||||
d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance windows:LayerBrushSettingsWindowViewModel}"
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using Artemis.UI.Shared.LayerBrushes;
|
||||
using Stylet;
|
||||
|
||||
@ -6,12 +7,36 @@ namespace Artemis.UI.Screens.ProfileEditor.Windows
|
||||
{
|
||||
public class LayerBrushSettingsWindowViewModel : Conductor<BrushConfigurationViewModel>
|
||||
{
|
||||
public LayerBrushSettingsWindowViewModel(BrushConfigurationViewModel configurationViewModel)
|
||||
private readonly LayerBrushConfigurationDialog _configuration;
|
||||
|
||||
public LayerBrushSettingsWindowViewModel(BrushConfigurationViewModel configurationViewModel, LayerBrushConfigurationDialog configuration)
|
||||
{
|
||||
_configuration = configuration;
|
||||
ActiveItem = configurationViewModel ?? throw new ArgumentNullException(nameof(configurationViewModel));
|
||||
ActiveItem.Closed += ActiveItemOnClosed;
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnViewLoaded()
|
||||
{
|
||||
// Setting the width/height via a binding and depending on WindowStartupLocation does not work
|
||||
Window window = View as Window;
|
||||
Window mainWindow = Application.Current.MainWindow;
|
||||
if (window == null || mainWindow == null)
|
||||
return;
|
||||
|
||||
window.Width = _configuration.DialogWidth;
|
||||
window.Height = _configuration.DialogHeight;
|
||||
window.Left = mainWindow.Left + (mainWindow.Width - window.Width) / 2;
|
||||
window.Top = mainWindow.Top + (mainWindow.Height - window.Height) / 2;
|
||||
|
||||
base.OnViewLoaded();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void ActiveItemOnClosed(object sender, CloseEventArgs e)
|
||||
{
|
||||
ActiveItem.Closed -= ActiveItemOnClosed;
|
||||
|
||||
@ -12,6 +12,8 @@
|
||||
Background="{DynamicResource MaterialDesignPaper}"
|
||||
FontFamily="pack://application:,,,/MaterialDesignThemes.Wpf;component/Resources/Roboto/#Roboto"
|
||||
UseLayoutRounding="True"
|
||||
MinWidth="400"
|
||||
MinHeight="400"
|
||||
Width="800"
|
||||
Height="800"
|
||||
d:DesignHeight="800"
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using Artemis.UI.Shared.LayerEffects;
|
||||
using Stylet;
|
||||
|
||||
@ -6,12 +7,36 @@ namespace Artemis.UI.Screens.ProfileEditor.Windows
|
||||
{
|
||||
public class LayerEffectSettingsWindowViewModel : Conductor<EffectConfigurationViewModel>
|
||||
{
|
||||
public LayerEffectSettingsWindowViewModel(EffectConfigurationViewModel configurationViewModel)
|
||||
private LayerEffectConfigurationDialog _configuration;
|
||||
|
||||
public LayerEffectSettingsWindowViewModel(EffectConfigurationViewModel configurationViewModel, LayerEffectConfigurationDialog configuration)
|
||||
{
|
||||
_configuration = configuration;
|
||||
ActiveItem = configurationViewModel ?? throw new ArgumentNullException(nameof(configurationViewModel));
|
||||
ActiveItem.Closed += ActiveItemOnClosed;
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnViewLoaded()
|
||||
{
|
||||
// Setting the width/height via a binding and depending on WindowStartupLocation does not work
|
||||
Window window = View as Window;
|
||||
Window mainWindow = Application.Current.MainWindow;
|
||||
if (window == null || mainWindow == null)
|
||||
return;
|
||||
|
||||
window.Width = _configuration.DialogWidth;
|
||||
window.Height = _configuration.DialogHeight;
|
||||
window.Left = mainWindow.Left + (mainWindow.Width - window.Width) / 2;
|
||||
window.Top = mainWindow.Top + (mainWindow.Height - window.Height) / 2;
|
||||
|
||||
base.OnViewLoaded();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void ActiveItemOnClosed(object sender, CloseEventArgs e)
|
||||
{
|
||||
ActiveItem.Closed -= ActiveItemOnClosed;
|
||||
|
||||
@ -21,6 +21,9 @@
|
||||
d:DesignHeight="800" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance device:DeviceDialogViewModel}"
|
||||
Icon="/Resources/Images/Logo/logo-512.png">
|
||||
<mde:MaterialWindow.Resources>
|
||||
<shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter"/>
|
||||
</mde:MaterialWindow.Resources>
|
||||
<mde:MaterialWindow.InputBindings>
|
||||
<KeyBinding Command="{s:Action ClearSelection}" Key="Escape" />
|
||||
</mde:MaterialWindow.InputBindings>
|
||||
@ -111,6 +114,14 @@
|
||||
VerticalAlignment="Center"
|
||||
ShowColors="True"
|
||||
LedClicked="{s:Action OnLedClicked}"/>
|
||||
|
||||
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
|
||||
Visibility="{Binding Device.Layout.RgbLayout.Author, Converter={StaticResource NullToVisibilityConverter}}"
|
||||
VerticalAlignment="Bottom"
|
||||
HorizontalAlignment="Left"
|
||||
Margin="15">
|
||||
Device layout by <Run FontWeight="Bold" Text="{Binding Device.Layout.RgbLayout.Author}"/>
|
||||
</TextBlock>
|
||||
</Grid>
|
||||
|
||||
<GridSplitter Grid.Column="1" Width="15" Margin="-15 0 0 0" Background="Transparent" HorizontalAlignment="Stretch" Panel.ZIndex="3" />
|
||||
|
||||
@ -12,6 +12,7 @@ using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using Ookii.Dialogs.Wpf;
|
||||
using RGB.NET.Core;
|
||||
using RGB.NET.Layout;
|
||||
using SkiaSharp;
|
||||
using Stylet;
|
||||
@ -42,14 +43,16 @@ namespace Artemis.UI.Screens.Settings.Device
|
||||
|
||||
Device = device;
|
||||
PanZoomViewModel = new PanZoomViewModel();
|
||||
SelectedLeds = new BindableCollection<ArtemisLed>();
|
||||
|
||||
Items.Add(factory.DevicePropertiesTabViewModel(device));
|
||||
if (device.RgbDevice.DeviceInfo.DeviceType == RGBDeviceType.Keyboard)
|
||||
Items.Add(factory.InputMappingsTabViewModel(device));
|
||||
Items.Add(factory.DeviceInfoTabViewModel(device));
|
||||
Items.Add(factory.DeviceLedsTabViewModel(device));
|
||||
|
||||
ActiveItem = Items.First();
|
||||
DisplayName = $"{device.RgbDevice.DeviceInfo.Model} | Artemis";
|
||||
|
||||
SelectedLeds = new BindableCollection<ArtemisLed>();
|
||||
}
|
||||
|
||||
public ArtemisDevice Device { get; }
|
||||
|
||||
@ -0,0 +1,83 @@
|
||||
<UserControl
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Settings.Device.Tabs"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:Shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared" x:Class="Artemis.UI.Screens.Settings.Device.Tabs.InputMappingsTabView"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance {x:Type local:InputMappingsTabViewModel}}">
|
||||
<UserControl.Resources>
|
||||
<ResourceDictionary>
|
||||
<Shared:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||
<Style x:Key="CenteredTextColumn" TargetType="TextBlock">
|
||||
<Setter Property="VerticalAlignment" Value="Center" />
|
||||
</Style>
|
||||
</ResourceDictionary>
|
||||
</UserControl.Resources>
|
||||
<Grid Margin="15">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Grid.Row="0">
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}">
|
||||
<Run Text="Introduction" />
|
||||
</TextBlock>
|
||||
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" TextWrapping="Wrap">
|
||||
In some cases you may want Artemis to map key presses to different LEDs.
|
||||
This is useful when your logical layout swaps keys around (like Hungarian layouts where the Z and Y keys are swapped).<LineBreak /><LineBreak />
|
||||
In this tab you can set up these custom input mappings, simply click on a LED and press a key, Artemis will from then on consider that LED pressed whenever you press the same key again.
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="1" Margin="0 20" Visibility="{Binding SelectedLed, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}">
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" TextAlignment="Center">Select a LED in the preview on the left side to get started...</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="1" Margin="0 20" Visibility="{Binding SelectedLed, Converter={StaticResource NullToVisibilityConverter}}">
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" TextAlignment="Center">
|
||||
<Run Text="Current target LED: " /><Run Text="{Binding SelectedLed.RgbLed.Id, Mode=OneWay}" />
|
||||
</TextBlock>
|
||||
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" TextAlignment="Center">
|
||||
<Run Text="Press the key you want to remap" /><Run Text=" " /><Run FontWeight="Bold" Text="{Binding SelectedLed.RgbLed.Id, Mode=OneWay}" /><Run Text=" " /><Run Text="to..." />
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<DataGrid Grid.Row="2"
|
||||
ItemsSource="{Binding InputMappings}"
|
||||
CanUserSortColumns="True"
|
||||
IsReadOnly="True"
|
||||
CanUserAddRows="False"
|
||||
AutoGenerateColumns="False"
|
||||
CanUserResizeRows="False"
|
||||
materialDesign:DataGridAssist.CellPadding="8"
|
||||
materialDesign:DataGridAssist.ColumnHeaderPadding="8"
|
||||
VirtualizingPanel.VirtualizationMode="Standard"
|
||||
Margin="10">
|
||||
<DataGrid.Columns>
|
||||
<materialDesign:DataGridTextColumn Binding="{Binding Item1.RgbLed.Id}" ElementStyle="{StaticResource CenteredTextColumn}" Header="Original LED ID" Width="*" />
|
||||
<materialDesign:DataGridTextColumn Binding="{Binding Item2.RgbLed.Id}" ElementStyle="{StaticResource CenteredTextColumn}" Header="Remapped LED ID" Width="*" />
|
||||
|
||||
<DataGridTemplateColumn Width="45" IsReadOnly="True">
|
||||
<DataGridTemplateColumn.CellTemplate>
|
||||
<DataTemplate>
|
||||
<Button Command="{s:Action DeleteMapping}"
|
||||
CommandParameter="{Binding}"
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
ToolTip="Delete mapping"
|
||||
Width="25"
|
||||
Height="25">
|
||||
<materialDesign:PackIcon Kind="Delete" Width="18" Height="18" />
|
||||
</Button>
|
||||
</DataTemplate>
|
||||
</DataGridTemplateColumn.CellTemplate>
|
||||
</DataGridTemplateColumn>
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
@ -0,0 +1,103 @@
|
||||
using System;
|
||||
using System.Collections.Specialized;
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Exceptions;
|
||||
using RGB.NET.Core;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.Settings.Device.Tabs
|
||||
{
|
||||
public class InputMappingsTabViewModel : Screen
|
||||
{
|
||||
private readonly IRgbService _rgbService;
|
||||
private readonly IInputService _inputService;
|
||||
private ArtemisLed _selectedLed;
|
||||
|
||||
public InputMappingsTabViewModel(ArtemisDevice device, IRgbService rgbService, IInputService inputService)
|
||||
{
|
||||
if (device.RgbDevice.DeviceInfo.DeviceType != RGBDeviceType.Keyboard)
|
||||
throw new ArtemisUIException("The input mappings tab only supports keyboards");
|
||||
_rgbService = rgbService;
|
||||
_inputService = inputService;
|
||||
|
||||
Device = device;
|
||||
DisplayName = "INPUT MAPPINGS";
|
||||
InputMappings = new BindableCollection<Tuple<ArtemisLed, ArtemisLed>>();
|
||||
}
|
||||
|
||||
public ArtemisDevice Device { get; }
|
||||
|
||||
public ArtemisLed SelectedLed
|
||||
{
|
||||
get => _selectedLed;
|
||||
set => SetAndNotify(ref _selectedLed, value);
|
||||
}
|
||||
|
||||
public BindableCollection<Tuple<ArtemisLed, ArtemisLed>> InputMappings { get; }
|
||||
|
||||
public void DeleteMapping(Tuple<ArtemisLed, ArtemisLed> inputMapping)
|
||||
{
|
||||
Device.InputMappings.Remove(inputMapping.Item1);
|
||||
UpdateInputMappings();
|
||||
}
|
||||
|
||||
private void InputServiceOnKeyboardKeyUp(object sender, ArtemisKeyboardKeyEventArgs e)
|
||||
{
|
||||
if (SelectedLed == null || e.Led == null)
|
||||
return;
|
||||
|
||||
// Locate the original LED the same way the InputService did it, but supply false to Device.GetLed
|
||||
bool foundLedId = InputKeyUtilities.KeyboardKeyLedIdMap.TryGetValue(e.Key, out LedId ledId);
|
||||
if (!foundLedId)
|
||||
return;
|
||||
ArtemisLed artemisLed = Device.GetLed(ledId, false);
|
||||
if (artemisLed == null)
|
||||
return;
|
||||
|
||||
// Apply the new LED mapping
|
||||
Device.InputMappings[SelectedLed] = artemisLed;
|
||||
_rgbService.SaveDevice(Device);
|
||||
((DeviceDialogViewModel) Parent).SelectedLeds.Clear();
|
||||
|
||||
UpdateInputMappings();
|
||||
}
|
||||
|
||||
private void UpdateInputMappings()
|
||||
{
|
||||
if (InputMappings.Any())
|
||||
InputMappings.Clear();
|
||||
|
||||
InputMappings.AddRange(Device.InputMappings.Select(m => new Tuple<ArtemisLed, ArtemisLed>(m.Key, m.Value)));
|
||||
}
|
||||
|
||||
private void SelectedLedsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
||||
{
|
||||
SelectedLed = ((DeviceDialogViewModel) Parent).SelectedLeds.FirstOrDefault();
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnActivate()
|
||||
{
|
||||
UpdateInputMappings();
|
||||
_inputService.KeyboardKeyUp += InputServiceOnKeyboardKeyUp;
|
||||
((DeviceDialogViewModel) Parent).SelectedLeds.CollectionChanged += SelectedLedsOnCollectionChanged;
|
||||
|
||||
base.OnActivate();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnDeactivate()
|
||||
{
|
||||
InputMappings.Clear();
|
||||
_inputService.KeyboardKeyUp -= InputServiceOnKeyboardKeyUp;
|
||||
((DeviceDialogViewModel) Parent).SelectedLeds.CollectionChanged -= SelectedLedsOnCollectionChanged;
|
||||
base.OnDeactivate();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -24,21 +24,28 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices
|
||||
_settingsVmFactory = settingsVmFactory;
|
||||
}
|
||||
|
||||
protected override void OnInitialActivate()
|
||||
#region Overrides of AllActive
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnActivate()
|
||||
{
|
||||
// Take it off the UI thread to avoid freezing on tab change
|
||||
Task.Run(async () =>
|
||||
{
|
||||
if (Items.Any())
|
||||
Items.Clear();
|
||||
|
||||
await Task.Delay(200);
|
||||
|
||||
List<DeviceSettingsViewModel> instances = _rgbService.Devices.Select(d => _settingsVmFactory.CreateDeviceSettingsViewModel(d)).ToList();
|
||||
foreach (DeviceSettingsViewModel deviceSettingsViewModel in instances)
|
||||
Items.Add(deviceSettingsViewModel);
|
||||
});
|
||||
|
||||
base.OnInitialActivate();
|
||||
base.OnActivate();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public async Task<bool> ShowDeviceDisableDialog()
|
||||
{
|
||||
if (_confirmedDisable)
|
||||
|
||||
@ -72,17 +72,17 @@
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Style="{StaticResource MaterialDesignTextBlock}">Startup delay</TextBlock>
|
||||
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap">
|
||||
Set the amount of seconds to wait before running Artemis with Windows. <LineBreak/>
|
||||
Set the amount of seconds to wait before running Artemis with Windows. <LineBreak />
|
||||
If some devices don't work because Artemis starts before the manufacturer's software, try increasing this value.
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
|
||||
<TextBox Style="{StaticResource MaterialDesignFilledTextBox}"
|
||||
Text="{Binding AutoRunDelay}"
|
||||
Text="{Binding AutoRunDelay}"
|
||||
IsEnabled="{Binding StartWithWindows}"
|
||||
Width="100"
|
||||
Width="100"
|
||||
materialDesign:TextFieldAssist.SuffixText="sec"
|
||||
materialDesign:HintAssist.IsFloating="false"/>
|
||||
materialDesign:HintAssist.IsFloating="false" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
|
||||
@ -103,13 +103,13 @@
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
|
||||
<ComboBox Style="{StaticResource MaterialDesignFilledComboBox}"
|
||||
<ComboBox Style="{StaticResource MaterialDesignFilledComboBox}"
|
||||
Width="100"
|
||||
SelectedValue="{Binding SelectedColorScheme}"
|
||||
ItemsSource="{Binding ColorSchemes}"
|
||||
SelectedValuePath="Value"
|
||||
DisplayMemberPath="Description"
|
||||
materialDesign:HintAssist.IsFloating="false"/>
|
||||
SelectedValue="{Binding SelectedColorScheme}"
|
||||
ItemsSource="{Binding ColorSchemes}"
|
||||
SelectedValuePath="Value"
|
||||
DisplayMemberPath="Description"
|
||||
materialDesign:HintAssist.IsFloating="false" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
|
||||
@ -130,13 +130,13 @@
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
|
||||
<ComboBox Style="{StaticResource MaterialDesignFilledComboBox}"
|
||||
<ComboBox Style="{StaticResource MaterialDesignFilledComboBox}"
|
||||
Width="100"
|
||||
SelectedValue="{Binding SelectedLogLevel}"
|
||||
ItemsSource="{Binding LogLevels}"
|
||||
SelectedValuePath="Value"
|
||||
SelectedValuePath="Value"
|
||||
DisplayMemberPath="Description"
|
||||
materialDesign:HintAssist.IsFloating="false"/>
|
||||
materialDesign:HintAssist.IsFloating="false" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
|
||||
@ -187,7 +187,7 @@
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
|
||||
<TextBox Style="{StaticResource MaterialDesignFilledTextBox}" Text="{Binding WebServerPortSetting.Value}" Width="100"
|
||||
materialDesign:HintAssist.IsFloating="false"/>
|
||||
materialDesign:HintAssist.IsFloating="false" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
@ -343,7 +343,7 @@
|
||||
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
|
||||
<ComboBox Style="{StaticResource MaterialDesignFilledComboBox}"
|
||||
Width="100"
|
||||
SelectedItem="{Binding PreferredGraphicsContext}"
|
||||
SelectedItem="{Binding PreferredGraphicsContext}"
|
||||
materialDesign:HintAssist.IsFloating="false">
|
||||
<system:String>Software</system:String>
|
||||
<system:String>Vulkan</system:String>
|
||||
@ -364,16 +364,17 @@
|
||||
<StackPanel Grid.Column="0">
|
||||
<TextBlock Style="{StaticResource MaterialDesignTextBlock}">Render scale</TextBlock>
|
||||
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap">
|
||||
Sets the resolution Artemis renders at, higher scale means more CPU-usage, especially on large surfaces.
|
||||
Sets the resolution Artemis renders at, higher scale means more CPU-usage, especially on large surfaces. <LineBreak />
|
||||
<Run Foreground="GoldenRod">A scale of 25% may be required for very large surfaces but could cause LED dimming or bleeding.</Run>
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
|
||||
<ComboBox Style="{StaticResource MaterialDesignFilledComboBox}"
|
||||
Width="100"
|
||||
SelectedItem="{Binding SelectedRenderScale}"
|
||||
ItemsSource="{Binding RenderScales}"
|
||||
SelectedItem="{Binding SelectedRenderScale}"
|
||||
ItemsSource="{Binding RenderScales}"
|
||||
DisplayMemberPath="Item1"
|
||||
materialDesign:HintAssist.IsFloating="false"/>
|
||||
materialDesign:HintAssist.IsFloating="false" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
|
||||
@ -399,7 +400,7 @@
|
||||
SelectedItem="{Binding SelectedTargetFrameRate}"
|
||||
ItemsSource="{Binding TargetFrameRates}"
|
||||
DisplayMemberPath="Item1"
|
||||
materialDesign:HintAssist.IsFloating="false"/>
|
||||
materialDesign:HintAssist.IsFloating="false" />
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user