1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Core - Provide BitmapBrush with the currently active surface

UI - Small style change to the confirmation dialog
Surface - Add API to get an ArtemisLed by its corresponding RGB.NET LED
Devices - Add API to get an ArtemisLed by its corresponding RGB.NET LED
Devices - Add API to get an ArtemisLed by its corresponding RGB.NET LedId
This commit is contained in:
SpoinkyNL 2020-12-04 23:35:13 +01:00
parent 5b0e1c91dd
commit f05740a5f1
10 changed files with 182 additions and 38 deletions

View File

@ -14,7 +14,6 @@ namespace Artemis.Core
/// </summary> /// </summary>
public class ArtemisDevice : CorePropertyChanged public class ArtemisDevice : CorePropertyChanged
{ {
private ReadOnlyCollection<ArtemisLed> _leds;
private SKPath? _renderPath; private SKPath? _renderPath;
private SKRect _renderRectangle; private SKRect _renderRectangle;
@ -28,13 +27,14 @@ namespace Artemis.Core
Rotation = 0; Rotation = 0;
Scale = 1; Scale = 1;
ZIndex = 1; ZIndex = 1;
deviceProvider.DeviceLayoutPaths.TryGetValue(rgbDevice, out string? layoutPath); deviceProvider.DeviceLayoutPaths.TryGetValue(rgbDevice, out string? layoutPath);
LayoutPath = layoutPath; LayoutPath = layoutPath;
InputIdentifiers = new List<ArtemisDeviceInputIdentifier>(); InputIdentifiers = new List<ArtemisDeviceInputIdentifier>();
_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));
ApplyToEntity(); ApplyToEntity();
CalculateRenderProperties(); CalculateRenderProperties();
} }
@ -45,7 +45,7 @@ namespace Artemis.Core
RgbDevice = rgbDevice; RgbDevice = rgbDevice;
DeviceProvider = deviceProvider; DeviceProvider = deviceProvider;
Surface = surface; Surface = surface;
deviceProvider.DeviceLayoutPaths.TryGetValue(rgbDevice, out string? layoutPath); deviceProvider.DeviceLayoutPaths.TryGetValue(rgbDevice, out string? layoutPath);
LayoutPath = layoutPath; LayoutPath = layoutPath;
@ -53,7 +53,8 @@ namespace Artemis.Core
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));
_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));
} }
/// <summary> /// <summary>
@ -92,11 +93,13 @@ namespace Artemis.Core
/// <summary> /// <summary>
/// Gets a read only collection containing the LEDs of this device /// Gets a read only collection containing the LEDs of this device
/// </summary> /// </summary>
public ReadOnlyCollection<ArtemisLed> Leds public ReadOnlyCollection<ArtemisLed> Leds { get; }
{
get => _leds; /// <summary>
private set => SetAndNotify(ref _leds, value); /// Gets a dictionary containing all the LEDs of this device with their corresponding RGB.NET <see cref="LedId" /> as
} /// key
/// </summary>
public ReadOnlyDictionary<LedId, ArtemisLed> LedIds { get; }
/// <summary> /// <summary>
/// Gets a list of input identifiers associated with this device /// Gets a list of input identifiers associated with this device
@ -182,16 +185,24 @@ namespace Artemis.Core
} }
/// <summary> /// <summary>
/// Occurs when the underlying RGB.NET device was updated /// Attempts to retrieve the <see cref="ArtemisLed" /> that corresponds the provided RGB.NET <see cref="Led" />
/// </summary> /// </summary>
public event EventHandler? DeviceUpdated; /// <param name="led">The RGB.NET <see cref="Led" /> to find the corresponding <see cref="ArtemisLed" /> for </param>
/// <returns>If found, the corresponding <see cref="ArtemisLed" />; otherwise <see langword="null" />.</returns>
public ArtemisLed? GetLed(Led led)
{
return GetLed(led.Id);
}
/// <summary> /// <summary>
/// Invokes the <see cref="DeviceUpdated" /> event /// Attempts to retrieve the <see cref="ArtemisLed" /> that corresponds the provided RGB.NET <see cref="LedId" />
/// </summary> /// </summary>
protected virtual void OnDeviceUpdated() /// <param name="ledId">The RGB.NET <see cref="LedId" /> to find the corresponding <see cref="ArtemisLed" /> for </param>
/// <returns>If found, the corresponding <see cref="ArtemisLed" />; otherwise <see langword="null" />.</returns>
public ArtemisLed? GetLed(LedId ledId)
{ {
DeviceUpdated?.Invoke(this, EventArgs.Empty); LedIds.TryGetValue(ledId, out ArtemisLed? artemisLed);
return artemisLed;
} }
internal void ApplyToEntity() internal void ApplyToEntity()
@ -247,5 +258,22 @@ namespace Artemis.Core
RenderPath = path; RenderPath = path;
} }
#region Events
/// <summary>
/// Occurs when the underlying RGB.NET device was updated
/// </summary>
public event EventHandler? DeviceUpdated;
/// <summary>
/// Invokes the <see cref="DeviceUpdated" /> event
/// </summary>
protected virtual void OnDeviceUpdated()
{
DeviceUpdated?.Invoke(this, EventArgs.Empty);
}
#endregion
} }
} }

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq; using System.Linq;
using Artemis.Storage.Entities.Surface; using Artemis.Storage.Entities.Surface;
using RGB.NET.Core; using RGB.NET.Core;
@ -11,7 +12,8 @@ namespace Artemis.Core
/// </summary> /// </summary>
public class ArtemisSurface : CorePropertyChanged public class ArtemisSurface : CorePropertyChanged
{ {
private List<ArtemisDevice> _devices; private List<ArtemisDevice> _devices = new List<ArtemisDevice>();
private ReadOnlyDictionary<Led, ArtemisLed> _ledMap = new ReadOnlyDictionary<Led, ArtemisLed>(new Dictionary<Led, ArtemisLed>());
private bool _isActive; private bool _isActive;
private string _name; private string _name;
private double _scale; private double _scale;
@ -26,9 +28,6 @@ namespace Artemis.Core
_scale = scale; _scale = scale;
_isActive = false; _isActive = false;
// Devices are not populated here but as they are detected
_devices = new List<ArtemisDevice>();
ApplyToEntity(); ApplyToEntity();
} }
@ -41,9 +40,6 @@ namespace Artemis.Core
_scale = scale; _scale = scale;
_name = surfaceEntity.Name; _name = surfaceEntity.Name;
_isActive = surfaceEntity.IsActive; _isActive = surfaceEntity.IsActive;
// Devices are not populated here but as they are detected
_devices = new List<ArtemisDevice>();
} }
/// <summary> /// <summary>
@ -87,6 +83,16 @@ namespace Artemis.Core
internal set => SetAndNotify(ref _devices, value); internal set => SetAndNotify(ref _devices, value);
} }
/// <summary>
/// Gets a dictionary containing all <see cref="ArtemisLed" />s on the surface with their corresponding RGB.NET
/// <see cref="Led" /> as key
/// </summary>
public ReadOnlyDictionary<Led, ArtemisLed> LedMap
{
get => _ledMap;
private set => SetAndNotify(ref _ledMap, value);
}
internal SurfaceEntity SurfaceEntity { get; set; } internal SurfaceEntity SurfaceEntity { get; set; }
internal Guid EntityId { get; set; } internal Guid EntityId { get; set; }
@ -103,6 +109,24 @@ namespace Artemis.Core
OnScaleChanged(); OnScaleChanged();
} }
/// <summary>
/// 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>
/// <returns>If found, the corresponding <see cref="ArtemisLed" />; otherwise <see langword="null" />.</returns>
public ArtemisLed? GetArtemisLed(Led led)
{
LedMap.TryGetValue(led, out ArtemisLed? artemisLed);
return artemisLed;
}
internal void UpdateLedMap()
{
LedMap = new ReadOnlyDictionary<Led, ArtemisLed>(
_devices.SelectMany(d => d.Leds.Select(al => new KeyValuePair<Led, ArtemisLed>(al.RgbLed, al))).ToDictionary(kvp => kvp.Key, kvp => kvp.Value)
);
}
internal void ApplyToEntity() internal void ApplyToEntity()
{ {
SurfaceEntity.Id = EntityId; SurfaceEntity.Id = EntityId;

View File

@ -176,6 +176,7 @@ namespace Artemis.Core
} }
internal bool IsDisposed { get; set; } internal bool IsDisposed { get; set; }
internal ArtemisSurface? Surface { get; set; }
#endregion #endregion
} }

View File

@ -192,11 +192,11 @@ namespace Artemis.Core.Services
if (UpdatePressedKeys(e.Device, e.Key, e.IsDown)) if (UpdatePressedKeys(e.Device, e.Key, e.IsDown))
return; return;
// Get the LED - TODO: leverage a lookup // Get the LED
bool foundLedId = InputKeyUtilities.KeyboardKeyLedIdMap.TryGetValue(e.Key, out LedId ledId); bool foundLedId = InputKeyUtilities.KeyboardKeyLedIdMap.TryGetValue(e.Key, out LedId ledId);
ArtemisLed? led = null; ArtemisLed? led = null;
if (foundLedId && e.Device != null) if (foundLedId && e.Device != null)
led = e.Device.Leds.FirstOrDefault(l => l.RgbLed.Id == ledId); led = e.Device.GetLed(ledId);
// Create the UpDown event args because it can be used for every event // Create the UpDown event args because it can be used for every event
ArtemisKeyboardKeyUpDownEventArgs eventArgs = new ArtemisKeyboardKeyUpDownEventArgs(e.Device, led, e.Key, keyboardModifierKey, e.IsDown); ArtemisKeyboardKeyUpDownEventArgs eventArgs = new ArtemisKeyboardKeyUpDownEventArgs(e.Device, led, e.Key, keyboardModifierKey, e.IsDown);

View File

@ -58,6 +58,7 @@ namespace Artemis.Core.Services
/// <summary> /// <summary>
/// Recalculates the LED group used by the <see cref="BitmapBrush" /> /// Recalculates the LED group used by the <see cref="BitmapBrush" />
/// </summary> /// </summary>
void UpdateSurfaceLedGroup(); /// <param name="artemisSurface"></param>
void UpdateSurfaceLedGroup(ArtemisSurface artemisSurface);
} }
} }

View File

@ -88,7 +88,8 @@ namespace Artemis.Core.Services
private void RenderScaleSettingOnSettingChanged(object? sender, EventArgs e) private void RenderScaleSettingOnSettingChanged(object? sender, EventArgs e)
{ {
UpdateSurfaceLedGroup(); // The surface hasn't changed so we can safely reuse it
UpdateSurfaceLedGroup(BitmapBrush?.Surface);
} }
private void TargetFrameRateSettingOnSettingChanged(object? sender, EventArgs e) private void TargetFrameRateSettingOnSettingChanged(object? sender, EventArgs e)
@ -107,8 +108,11 @@ namespace Artemis.Core.Services
public event EventHandler<DeviceEventArgs>? DeviceLoaded; public event EventHandler<DeviceEventArgs>? DeviceLoaded;
public event EventHandler<DeviceEventArgs>? DeviceReloaded; public event EventHandler<DeviceEventArgs>? DeviceReloaded;
public void UpdateSurfaceLedGroup() public void UpdateSurfaceLedGroup(ArtemisSurface? artemisSurface)
{ {
if (artemisSurface == null)
return;
if (_surfaceLedGroup == null || BitmapBrush == null) if (_surfaceLedGroup == null || BitmapBrush == null)
{ {
// Apply the application wide brush and decorator // Apply the application wide brush and decorator
@ -124,6 +128,7 @@ namespace Artemis.Core.Services
// Apply the application wide brush and decorator // Apply the application wide brush and decorator
BitmapBrush.Scale = new Scale(_renderScaleSetting.Value); BitmapBrush.Scale = new Scale(_renderScaleSetting.Value);
BitmapBrush.Surface = artemisSurface;
_surfaceLedGroup = new ListLedGroup(Surface.Leds) {Brush = BitmapBrush}; _surfaceLedGroup = new ListLedGroup(Surface.Leds) {Brush = BitmapBrush};
} }
} }

View File

@ -0,0 +1,24 @@
using System.Collections.Generic;
using RGB.NET.Core;
namespace Artemis.Core.Services.Models
{
internal class SurfaceArrangement
{
public SurfaceArrangement()
{
Devices = new List<SurfaceArrangementDevice>();
}
public List<SurfaceArrangementDevice> Devices { get; }
internal static SurfaceArrangement GetDefaultArrangement()
{
SurfaceArrangement arrangement = new SurfaceArrangement();
arrangement.Devices.Add(new SurfaceArrangementDevice(null, RGBDeviceType.Keyboard, ArrangementPosition.Right));
return arrangement;
}
}
}

View File

@ -0,0 +1,43 @@
using System.Collections.Generic;
using System.Linq;
using RGB.NET.Core;
namespace Artemis.Core.Services.Models
{
internal class SurfaceArrangementDevice
{
public SurfaceArrangementDevice? Anchor { get; }
public RGBDeviceType DeviceType { get; }
public ArrangementPosition Position { get; }
public SurfaceArrangementDevice(SurfaceArrangementDevice? anchor, RGBDeviceType deviceType, ArrangementPosition position)
{
Anchor = anchor;
DeviceType = deviceType;
Position = position;
}
public void Apply(ArtemisSurface surface)
{
List<ArtemisDevice> devices = surface.Devices.Where(d => d.RgbDevice.DeviceInfo.DeviceType == DeviceType).ToList();
ArtemisDevice? previous = null;
foreach (ArtemisDevice artemisDevice in devices)
{
if (previous != null)
{
}
previous = artemisDevice;
}
}
}
internal enum ArrangementPosition
{
Left,
Right,
Top,
Bottom,
Center
}
}

View File

@ -88,7 +88,7 @@ namespace Artemis.Core.Services
device.ApplyToRgbDevice(); device.ApplyToRgbDevice();
// Update the RGB service's graphics decorator to work with the new surface entity // Update the RGB service's graphics decorator to work with the new surface entity
_rgbService.UpdateSurfaceLedGroup(); _rgbService.UpdateSurfaceLedGroup(ActiveSurface);
OnActiveSurfaceConfigurationChanged(new SurfaceConfigurationEventArgs(ActiveSurface)); OnActiveSurfaceConfigurationChanged(new SurfaceConfigurationEventArgs(ActiveSurface));
} }
@ -104,9 +104,10 @@ namespace Artemis.Core.Services
deviceConfiguration.ApplyToRgbDevice(); deviceConfiguration.ApplyToRgbDevice();
} }
} }
surface.UpdateLedMap();
_surfaceRepository.Save(surface.SurfaceEntity); _surfaceRepository.Save(surface.SurfaceEntity);
_rgbService.UpdateSurfaceLedGroup(); _rgbService.UpdateSurfaceLedGroup(ActiveSurface);
OnSurfaceConfigurationUpdated(new SurfaceConfigurationEventArgs(surface)); OnSurfaceConfigurationUpdated(new SurfaceConfigurationEventArgs(surface));
} }
@ -199,6 +200,19 @@ namespace Artemis.Core.Services
#endregion #endregion
#region AutoLayout
public void AutoLayout()
{
// Phase one, bottom layer
// Keyboard
// Phase two, top layer
}
#endregion
#region Event handlers #region Event handlers
private void RgbServiceOnDeviceLoaded(object? sender, DeviceEventArgs e) private void RgbServiceOnDeviceLoaded(object? sender, DeviceEventArgs e)

View File

@ -11,19 +11,23 @@
d:DataContext="{d:DesignInstance dialogs:ConfirmDialogViewModel}"> d:DataContext="{d:DesignInstance dialogs:ConfirmDialogViewModel}">
<StackPanel Margin="16"> <StackPanel Margin="16">
<TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" Text="{Binding Header}" TextWrapping="Wrap" /> <TextBlock Style="{StaticResource MaterialDesignHeadline6TextBlock}" Text="{Binding Header}" TextWrapping="Wrap" />
<TextBlock Style="{StaticResource MaterialDesignBody1TextBlock}" Margin="0 20 0 20" Text="{Binding Text}" TextWrapping="Wrap" /> <TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}"
Foreground="{DynamicResource MaterialDesignBodyLight}"
Margin="0 20 0 20"
Text="{Binding Text}"
TextWrapping="Wrap" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0 8 0 0"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0 8 0 0">
<Button Style="{StaticResource MaterialDesignFlatButton}" <Button Style="{StaticResource MaterialDesignFlatButton}"
Focusable="False" Focusable="False"
IsCancel="True" IsCancel="True"
Command="{s:Action Cancel}" Command="{s:Action Cancel}"
Content="{Binding CancelText}" /> Content="{Binding CancelText}" />
<Button x:Name="ConfirmButton" <Button x:Name="ConfirmButton"
Style="{StaticResource MaterialDesignFlatButton}" Style="{StaticResource MaterialDesignFlatButton}"
IsDefault="True" IsDefault="True"
Focusable="True" Focusable="True"
Command="{s:Action Confirm}" Command="{s:Action Confirm}"
Content="{Binding ConfirmText}" /> Content="{Binding ConfirmText}" />
</StackPanel> </StackPanel>