mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Profiles - Added profile adaption based on configurable hints
Layers - Added hints UI accesible from profile tree Surface - Added device categories used by profile adaption
This commit is contained in:
parent
4865254ab6
commit
57193e739e
@ -1,5 +1,8 @@
|
||||
<wpf:ResourceDictionary xml:space="preserve" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:s="clr-namespace:System;assembly=mscorlib" xmlns:ss="urn:shemas-jetbrains-com:settings-storage-xaml" xmlns:wpf="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=defaulttypes/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cadaption/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cadaptionhints/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cadaption_005Chints/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cconditions_005Cwrappers/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cdatabindings_005Cmodes/@EntryIndexedValue">True</s:Boolean>
|
||||
<s:Boolean x:Key="/Default/CodeInspection/NamespaceProvider/NamespaceFoldersToSkip/=models_005Cprofile_005Cdatabindings_005Cmodes_005Cconditional/@EntryIndexedValue">True</s:Boolean>
|
||||
|
||||
@ -0,0 +1,75 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Storage.Entities.Profile.AdaptionHints;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a hint that adapts layers to a certain category of devices
|
||||
/// </summary>
|
||||
public class CategoryAdaptionHint : IAdaptionHint
|
||||
{
|
||||
public CategoryAdaptionHint()
|
||||
{
|
||||
}
|
||||
|
||||
internal CategoryAdaptionHint(CategoryAdaptionHintEntity entity)
|
||||
{
|
||||
Category = (DeviceCategory) entity.Category;
|
||||
Skip = entity.Skip;
|
||||
LimitAmount = entity.LimitAmount;
|
||||
Amount = entity.Amount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the category of devices LEDs will be applied to
|
||||
/// </summary>
|
||||
public DeviceCategory Category { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the amount of devices to skip
|
||||
/// </summary>
|
||||
public int Skip { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a boolean indicating whether a limited amount of devices should be used
|
||||
/// </summary>
|
||||
public bool LimitAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the amount of devices to limit to if <see cref="LimitAmount" /> is <see langword="true" />
|
||||
/// </summary>
|
||||
public int Amount { get; set; }
|
||||
|
||||
#region Implementation of IAdaptionHint
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Apply(Layer layer, List<ArtemisDevice> devices)
|
||||
{
|
||||
IEnumerable<ArtemisDevice> matches = devices
|
||||
.Where(d => d.Categories.Contains(Category))
|
||||
.OrderBy(d => d.Rectangle.Top)
|
||||
.ThenBy(d => d.Rectangle.Left)
|
||||
.Skip(Skip);
|
||||
if (LimitAmount)
|
||||
matches = matches.Take(Amount);
|
||||
|
||||
foreach (ArtemisDevice artemisDevice in matches)
|
||||
layer.AddLeds(artemisDevice.Leds);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IAdaptionHintEntity GetEntry()
|
||||
{
|
||||
return new CategoryAdaptionHintEntity {Amount = Amount, LimitAmount = LimitAmount, Category = (int) Category, Skip = Skip};
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Category adaption - {nameof(Category)}: {Category}, {nameof(Skip)}: {Skip}, {nameof(LimitAmount)}: {LimitAmount}, {nameof(Amount)}: {Amount}";
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,76 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Storage.Entities.Profile.AdaptionHints;
|
||||
using RGB.NET.Core;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a hint that adapts layers to a certain type of devices
|
||||
/// </summary>
|
||||
public class DeviceAdaptionHint : IAdaptionHint
|
||||
{
|
||||
public DeviceAdaptionHint()
|
||||
{
|
||||
}
|
||||
|
||||
internal DeviceAdaptionHint(DeviceAdaptionHintEntity entity)
|
||||
{
|
||||
DeviceType = (RGBDeviceType) entity.DeviceType;
|
||||
Skip = entity.Skip;
|
||||
LimitAmount = entity.LimitAmount;
|
||||
Amount = entity.Amount;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the type of devices LEDs will be applied to
|
||||
/// </summary>
|
||||
public RGBDeviceType DeviceType { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the amount of devices to skip
|
||||
/// </summary>
|
||||
public int Skip { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a boolean indicating whether a limited amount of devices should be used
|
||||
/// </summary>
|
||||
public bool LimitAmount { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the amount of devices to limit to if <see cref="LimitAmount" /> is <see langword="true" />
|
||||
/// </summary>
|
||||
public int Amount { get; set; }
|
||||
|
||||
#region Implementation of IAdaptionHint
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Apply(Layer layer, List<ArtemisDevice> devices)
|
||||
{
|
||||
IEnumerable<ArtemisDevice> matches = devices
|
||||
.Where(d => d.RgbDevice.DeviceInfo.DeviceType == DeviceType)
|
||||
.OrderBy(d => d.Rectangle.Top)
|
||||
.ThenBy(d => d.Rectangle.Left)
|
||||
.Skip(Skip);
|
||||
if (LimitAmount)
|
||||
matches = matches.Take(Amount);
|
||||
|
||||
foreach (ArtemisDevice artemisDevice in matches)
|
||||
layer.AddLeds(artemisDevice.Leds);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IAdaptionHintEntity GetEntry()
|
||||
{
|
||||
return new DeviceAdaptionHintEntity {Amount = Amount, LimitAmount = LimitAmount, DeviceType = (int) DeviceType, Skip = Skip};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Device adaption - {nameof(DeviceType)}: {DeviceType}, {nameof(Skip)}: {Skip}, {nameof(LimitAmount)}: {LimitAmount}, {nameof(Amount)}: {Amount}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
using System.Collections.Generic;
|
||||
using Artemis.Storage.Entities.Profile.AdaptionHints;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an adaption hint that's used to adapt a layer to a set of devices
|
||||
/// </summary>
|
||||
public interface IAdaptionHint
|
||||
{
|
||||
/// <summary>
|
||||
/// Applies the adaptive action to the provided layer
|
||||
/// </summary>
|
||||
/// <param name="layer">The layer to adapt</param>
|
||||
/// <param name="devices">The devices to adapt the layer for</param>
|
||||
void Apply(Layer layer, List<ArtemisDevice> devices);
|
||||
|
||||
/// <summary>
|
||||
/// Returns an adaption hint entry for this adaption hint used for persistent storage
|
||||
/// </summary>
|
||||
IAdaptionHintEntity GetEntry();
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,83 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Storage.Entities.Profile.AdaptionHints;
|
||||
using RGB.NET.Core;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents a hint that adapts layers to a certain region of keyboards
|
||||
/// </summary>
|
||||
public class KeyboardSectionAdaptionHint : IAdaptionHint
|
||||
{
|
||||
private static readonly Dictionary<KeyboardSection, List<LedId>> RegionLedIds = new()
|
||||
{
|
||||
{KeyboardSection.MacroKeys, Enum.GetValues<LedId>().Where(l => l >= LedId.Keyboard_Programmable1 && l <= LedId.Keyboard_Programmable32).ToList()},
|
||||
{KeyboardSection.LedStrips, Enum.GetValues<LedId>().Where(l => l >= LedId.LedStripe1 && l <= LedId.LedStripe128).ToList()},
|
||||
{KeyboardSection.Extra, Enum.GetValues<LedId>().Where(l => l >= LedId.Keyboard_Custom1 && l <= LedId.Keyboard_Custom64).ToList()}
|
||||
};
|
||||
|
||||
public KeyboardSectionAdaptionHint()
|
||||
{
|
||||
}
|
||||
|
||||
internal KeyboardSectionAdaptionHint(KeyboardSectionAdaptionHintEntity entity)
|
||||
{
|
||||
Section = (KeyboardSection) entity.Section;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the section this hint will apply LEDs to
|
||||
/// </summary>
|
||||
public KeyboardSection Section { get; set; }
|
||||
|
||||
#region Implementation of IAdaptionHint
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Apply(Layer layer, List<ArtemisDevice> devices)
|
||||
{
|
||||
// Only keyboards should have the LEDs we care about
|
||||
foreach (ArtemisDevice keyboard in devices.Where(d => d.RgbDevice.DeviceInfo.DeviceType == RGBDeviceType.Keyboard))
|
||||
{
|
||||
List<LedId> ledIds = RegionLedIds[Section];
|
||||
layer.AddLeds(keyboard.Leds.Where(l => ledIds.Contains(l.RgbLed.Id)));
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public IAdaptionHintEntity GetEntry()
|
||||
{
|
||||
return new KeyboardSectionAdaptionHintEntity {Section = (int) Section};
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override string ToString()
|
||||
{
|
||||
return $"Keyboard section adaption - {nameof(Section)}: {Section}";
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Represents a section of LEDs on a keyboard
|
||||
/// </summary>
|
||||
public enum KeyboardSection
|
||||
{
|
||||
/// <summary>
|
||||
/// A region containing the macro keys of a keyboard
|
||||
/// </summary>
|
||||
MacroKeys,
|
||||
|
||||
/// <summary>
|
||||
/// A region containing the LED strips of a keyboard
|
||||
/// </summary>
|
||||
LedStrips,
|
||||
|
||||
/// <summary>
|
||||
/// A region containing extra non-standard LEDs of a keyboard
|
||||
/// </summary>
|
||||
Extra
|
||||
}
|
||||
}
|
||||
@ -7,6 +7,7 @@ using Artemis.Core.LayerBrushes;
|
||||
using Artemis.Core.LayerEffects;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using Artemis.Storage.Entities.Profile.Abstract;
|
||||
using RGB.NET.Core;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.Core
|
||||
@ -42,6 +43,7 @@ namespace Artemis.Core
|
||||
|
||||
_leds = new List<ArtemisLed>();
|
||||
|
||||
Adapter = new LayerAdapter(this);
|
||||
Initialize();
|
||||
Parent.AddChild(this, 0);
|
||||
}
|
||||
@ -65,6 +67,7 @@ namespace Artemis.Core
|
||||
_leds = new List<ArtemisLed>();
|
||||
|
||||
Load();
|
||||
Adapter = new LayerAdapter(this);
|
||||
Initialize();
|
||||
}
|
||||
|
||||
@ -121,6 +124,11 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public LayerEntity LayerEntity { get; internal set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the layer adapter that can be used to adapt this layer to a different set of devices
|
||||
/// </summary>
|
||||
public LayerAdapter Adapter { get; }
|
||||
|
||||
/// <inheritdoc />
|
||||
public override bool ShouldBeEnabled => !Suspended && DisplayConditionMet;
|
||||
|
||||
@ -147,7 +155,15 @@ namespace Artemis.Core
|
||||
return $"[Layer] {nameof(Name)}: {Name}, {nameof(Order)}: {Order}";
|
||||
}
|
||||
|
||||
#region IDisposable
|
||||
/// <summary>
|
||||
/// Occurs when a property affecting the rendering properties of this layer has been updated
|
||||
/// </summary>
|
||||
public event EventHandler? RenderPropertiesUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the layer brush of this layer has been updated
|
||||
/// </summary>
|
||||
public event EventHandler? LayerBrushUpdated;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Dispose(bool disposing)
|
||||
@ -162,7 +178,10 @@ namespace Artemis.Core
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#endregion
|
||||
internal void OnLayerBrushUpdated()
|
||||
{
|
||||
LayerBrushUpdated?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
@ -190,6 +209,28 @@ namespace Artemis.Core
|
||||
Reset();
|
||||
}
|
||||
|
||||
private void LayerBrushStoreOnLayerBrushRemoved(object? sender, LayerBrushStoreEvent e)
|
||||
{
|
||||
if (LayerBrush?.Descriptor == e.Registration.LayerBrushDescriptor)
|
||||
DeactivateLayerBrush();
|
||||
}
|
||||
|
||||
private void LayerBrushStoreOnLayerBrushAdded(object? sender, LayerBrushStoreEvent e)
|
||||
{
|
||||
if (LayerBrush != null || !General.PropertiesInitialized)
|
||||
return;
|
||||
|
||||
LayerBrushReference? current = General.BrushReference.CurrentValue;
|
||||
if (e.Registration.PluginFeature.Id == current?.LayerBrushProviderId &&
|
||||
e.Registration.LayerBrushDescriptor.LayerBrushType.Name == current.BrushType)
|
||||
ActivateLayerBrush();
|
||||
}
|
||||
|
||||
private void OnRenderPropertiesUpdated()
|
||||
{
|
||||
RenderPropertiesUpdated?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
#region Storage
|
||||
|
||||
internal override void Load()
|
||||
@ -229,7 +270,8 @@ namespace Artemis.Core
|
||||
LedEntity ledEntity = new()
|
||||
{
|
||||
DeviceIdentifier = artemisLed.Device.Identifier,
|
||||
LedName = artemisLed.RgbLed.Id.ToString()
|
||||
LedName = artemisLed.RgbLed.Id.ToString(),
|
||||
PhysicalLayout = artemisLed.Device.RgbDevice.DeviceInfo.DeviceType == RGBDeviceType.Keyboard ? (int) artemisLed.Device.PhysicalLayout : null
|
||||
};
|
||||
LayerEntity.Leds.Add(ledEntity);
|
||||
}
|
||||
@ -575,7 +617,7 @@ namespace Artemis.Core
|
||||
if (Disposed)
|
||||
throw new ObjectDisposedException("Layer");
|
||||
|
||||
_leds.AddRange(leds);
|
||||
_leds.AddRange(leds.Except(_leds));
|
||||
CalculateRenderProperties();
|
||||
}
|
||||
|
||||
@ -692,51 +734,6 @@ namespace Artemis.Core
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void LayerBrushStoreOnLayerBrushRemoved(object? sender, LayerBrushStoreEvent e)
|
||||
{
|
||||
if (LayerBrush?.Descriptor == e.Registration.LayerBrushDescriptor)
|
||||
DeactivateLayerBrush();
|
||||
}
|
||||
|
||||
private void LayerBrushStoreOnLayerBrushAdded(object? sender, LayerBrushStoreEvent e)
|
||||
{
|
||||
if (LayerBrush != null || !General.PropertiesInitialized)
|
||||
return;
|
||||
|
||||
LayerBrushReference? current = General.BrushReference.CurrentValue;
|
||||
if (e.Registration.PluginFeature.Id == current?.LayerBrushProviderId &&
|
||||
e.Registration.LayerBrushDescriptor.LayerBrushType.Name == current.BrushType)
|
||||
ActivateLayerBrush();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Events
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a property affecting the rendering properties of this layer has been updated
|
||||
/// </summary>
|
||||
public event EventHandler? RenderPropertiesUpdated;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the layer brush of this layer has been updated
|
||||
/// </summary>
|
||||
public event EventHandler? LayerBrushUpdated;
|
||||
|
||||
private void OnRenderPropertiesUpdated()
|
||||
{
|
||||
RenderPropertiesUpdated?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
internal void OnLayerBrushUpdated()
|
||||
{
|
||||
LayerBrushUpdated?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
144
src/Artemis.Core/Models/Profile/LayerAdapter.cs
Normal file
144
src/Artemis.Core/Models/Profile/LayerAdapter.cs
Normal file
@ -0,0 +1,144 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using Artemis.Storage.Entities.Profile.AdaptionHints;
|
||||
using RGB.NET.Core;
|
||||
|
||||
namespace Artemis.Core
|
||||
{
|
||||
/// <summary>
|
||||
/// Represents an adapter that adapts a layer to a certain set of devices using <see cref="IAdaptionHint" />s
|
||||
/// </summary>
|
||||
public class LayerAdapter : IStorageModel
|
||||
{
|
||||
internal LayerAdapter(Layer layer)
|
||||
{
|
||||
Layer = layer;
|
||||
AdaptionHints = new List<IAdaptionHint>();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the layer this adapter can adapt
|
||||
/// </summary>
|
||||
public Layer Layer { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a list containing the adaption hints used by this adapter
|
||||
/// </summary>
|
||||
public List<IAdaptionHint> AdaptionHints { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Modifies the layer, adapting it to the provided <paramref name="devices" />
|
||||
/// </summary>
|
||||
/// <param name="devices">The devices to adapt the layer to</param>
|
||||
public void Adapt(List<ArtemisDevice> devices)
|
||||
{
|
||||
// Use adaption hints if provided
|
||||
if (AdaptionHints.Any())
|
||||
{
|
||||
foreach (IAdaptionHint adaptionHint in AdaptionHints)
|
||||
adaptionHint.Apply(Layer, devices);
|
||||
}
|
||||
// If there are no hints, try to find matching LEDs anyway
|
||||
else
|
||||
{
|
||||
List<ArtemisLed> availableLeds = devices.SelectMany(d => d.Leds).ToList();
|
||||
List<ArtemisLed> usedLeds = new();
|
||||
|
||||
foreach (LedEntity ledEntity in Layer.LayerEntity.Leds)
|
||||
{
|
||||
// TODO: If this is a keyboard LED and the layouts don't match, convert it before looking for it on the devices
|
||||
|
||||
LedId ledId = Enum.Parse<LedId>(ledEntity.LedName);
|
||||
ArtemisLed? led = availableLeds.FirstOrDefault(l => l.RgbLed.Id == ledId);
|
||||
|
||||
if (led != null)
|
||||
{
|
||||
availableLeds.Remove(led);
|
||||
usedLeds.Add(led);
|
||||
}
|
||||
}
|
||||
|
||||
Layer.AddLeds(usedLeds);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Automatically determine hints for this layer
|
||||
/// </summary>
|
||||
public List<IAdaptionHint> DetermineHints(IEnumerable<ArtemisDevice> devices)
|
||||
{
|
||||
List<IAdaptionHint> newHints = new();
|
||||
// Any fully covered device will add a device adaption hint for that type
|
||||
foreach (IGrouping<ArtemisDevice, ArtemisLed> deviceLeds in Layer.Leds.GroupBy(l => l.Device))
|
||||
{
|
||||
ArtemisDevice device = deviceLeds.Key;
|
||||
// If there is already an adaption hint for this type, don't add another
|
||||
if (AdaptionHints.Any(h => h is DeviceAdaptionHint d && d.DeviceType == device.RgbDevice.DeviceInfo.DeviceType))
|
||||
continue;
|
||||
if (DoesLayerCoverDevice(device))
|
||||
{
|
||||
DeviceAdaptionHint hint = new() {DeviceType = device.RgbDevice.DeviceInfo.DeviceType};
|
||||
AdaptionHints.Add(hint);
|
||||
newHints.Add(hint);
|
||||
}
|
||||
}
|
||||
|
||||
// Any fully covered category will add a category adaption hint for its category
|
||||
foreach (DeviceCategory deviceCategory in Enum.GetValues<DeviceCategory>())
|
||||
{
|
||||
if (AdaptionHints.Any(h => h is CategoryAdaptionHint c && c.Category == deviceCategory))
|
||||
continue;
|
||||
|
||||
List<ArtemisDevice> categoryDevices = devices.Where(d => d.Categories.Contains(deviceCategory)).ToList();
|
||||
if (categoryDevices.Any() && categoryDevices.All(DoesLayerCoverDevice))
|
||||
{
|
||||
CategoryAdaptionHint hint = new() {Category = deviceCategory};
|
||||
AdaptionHints.Add(hint);
|
||||
newHints.Add(hint);
|
||||
}
|
||||
}
|
||||
|
||||
return newHints;
|
||||
}
|
||||
|
||||
private bool DoesLayerCoverDevice(ArtemisDevice device)
|
||||
{
|
||||
return device.Leds.All(l => Layer.Leds.Contains(l));
|
||||
}
|
||||
|
||||
#region Implementation of IStorageModel
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Load()
|
||||
{
|
||||
AdaptionHints.Clear();
|
||||
// Kind of meh.
|
||||
// This leaves the adapter responsible for finding the right hint for the right entity, but it's gotta be done somewhere..
|
||||
foreach (IAdaptionHintEntity hintEntity in Layer.LayerEntity.AdaptionHints)
|
||||
switch (hintEntity)
|
||||
{
|
||||
case DeviceAdaptionHintEntity entity:
|
||||
AdaptionHints.Add(new DeviceAdaptionHint(entity));
|
||||
break;
|
||||
case CategoryAdaptionHintEntity entity:
|
||||
AdaptionHints.Add(new CategoryAdaptionHint(entity));
|
||||
break;
|
||||
case KeyboardSectionAdaptionHintEntity entity:
|
||||
AdaptionHints.Add(new KeyboardSectionAdaptionHint(entity));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Save()
|
||||
{
|
||||
Layer.LayerEntity.AdaptionHints.Clear();
|
||||
foreach (IAdaptionHint adaptionHint in AdaptionHints)
|
||||
Layer.LayerEntity.AdaptionHints.Add(adaptionHint.GetEntry());
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -36,10 +36,12 @@ namespace Artemis.Core
|
||||
|
||||
InputIdentifiers = new List<ArtemisDeviceInputIdentifier>();
|
||||
InputMappings = new Dictionary<ArtemisLed, ArtemisLed>();
|
||||
Categories = new HashSet<DeviceCategory>();
|
||||
|
||||
UpdateLeds();
|
||||
ApplyKeyboardLayout();
|
||||
ApplyToEntity();
|
||||
ApplyDefaultCategories();
|
||||
CalculateRenderProperties();
|
||||
}
|
||||
|
||||
@ -52,6 +54,7 @@ namespace Artemis.Core
|
||||
|
||||
InputIdentifiers = new List<ArtemisDeviceInputIdentifier>();
|
||||
InputMappings = new Dictionary<ArtemisLed, ArtemisLed>();
|
||||
Categories = new HashSet<DeviceCategory>();
|
||||
|
||||
foreach (DeviceInputIdentifierEntity identifierEntity in DeviceEntity.InputIdentifiers)
|
||||
InputIdentifiers.Add(new ArtemisDeviceInputIdentifier(identifierEntity.InputProvider, identifierEntity.Identifier));
|
||||
@ -114,6 +117,11 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public Dictionary<ArtemisLed, ArtemisLed> InputMappings { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets a list containing the categories of this device
|
||||
/// </summary>
|
||||
public HashSet<DeviceCategory> Categories { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the X-position of the device
|
||||
/// </summary>
|
||||
@ -383,6 +391,46 @@ namespace Artemis.Core
|
||||
OnDeviceUpdated();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Applies the default categories for this device to the <see cref="Categories"/> list
|
||||
/// </summary>
|
||||
public void ApplyDefaultCategories()
|
||||
{
|
||||
switch (RgbDevice.DeviceInfo.DeviceType)
|
||||
{
|
||||
case RGBDeviceType.Keyboard:
|
||||
case RGBDeviceType.Mouse:
|
||||
case RGBDeviceType.Headset:
|
||||
case RGBDeviceType.Mousepad:
|
||||
case RGBDeviceType.HeadsetStand:
|
||||
case RGBDeviceType.Keypad:
|
||||
if (!Categories.Contains(DeviceCategory.Peripherals))
|
||||
Categories.Add(DeviceCategory.Peripherals);
|
||||
break;
|
||||
case RGBDeviceType.Mainboard:
|
||||
case RGBDeviceType.GraphicsCard:
|
||||
case RGBDeviceType.DRAM:
|
||||
case RGBDeviceType.Fan:
|
||||
case RGBDeviceType.LedStripe:
|
||||
case RGBDeviceType.Cooler:
|
||||
if (!Categories.Contains(DeviceCategory.Case))
|
||||
Categories.Add(DeviceCategory.Case);
|
||||
break;
|
||||
case RGBDeviceType.Speaker:
|
||||
if (!Categories.Contains(DeviceCategory.Desk))
|
||||
Categories.Add(DeviceCategory.Desk);
|
||||
break;
|
||||
case RGBDeviceType.Monitor:
|
||||
if (!Categories.Contains(DeviceCategory.Monitor))
|
||||
Categories.Add(DeviceCategory.Monitor);
|
||||
break;
|
||||
case RGBDeviceType.LedMatrix:
|
||||
if (!Categories.Contains(DeviceCategory.Room))
|
||||
Categories.Add(DeviceCategory.Room);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
internal void ApplyToEntity()
|
||||
{
|
||||
// Other properties are computed
|
||||
@ -401,6 +449,10 @@ namespace Artemis.Core
|
||||
DeviceEntity.InputMappings.Clear();
|
||||
foreach (var (original, mapped) in InputMappings)
|
||||
DeviceEntity.InputMappings.Add(new InputMappingEntity {OriginalLedId = (int) original.RgbLed.Id, MappedLedId = (int) mapped.RgbLed.Id});
|
||||
|
||||
DeviceEntity.Categories.Clear();
|
||||
foreach (DeviceCategory deviceCategory in Categories)
|
||||
DeviceEntity.Categories.Add((int) deviceCategory);
|
||||
}
|
||||
|
||||
internal void ApplyToRgbDevice()
|
||||
@ -419,6 +471,12 @@ namespace Artemis.Core
|
||||
|
||||
if (!RgbDevice.ColorCorrections.Any())
|
||||
RgbDevice.ColorCorrections.Add(new ScaleColorCorrection(this));
|
||||
|
||||
Categories.Clear();
|
||||
foreach (int deviceEntityCategory in DeviceEntity.Categories)
|
||||
Categories.Add((DeviceCategory) deviceEntityCategory);
|
||||
if (!Categories.Any())
|
||||
ApplyDefaultCategories();
|
||||
|
||||
CalculateRenderProperties();
|
||||
OnDeviceUpdated();
|
||||
@ -472,4 +530,13 @@ namespace Artemis.Core
|
||||
LogicalLayout = DeviceEntity.LogicalLayout;
|
||||
}
|
||||
}
|
||||
|
||||
public enum DeviceCategory
|
||||
{
|
||||
Desk,
|
||||
Monitor,
|
||||
Case,
|
||||
Room,
|
||||
Peripherals
|
||||
}
|
||||
}
|
||||
@ -314,6 +314,9 @@ namespace Artemis.Core.Services
|
||||
{
|
||||
SurfaceArrangement surfaceArrangement = SurfaceArrangement.GetDefaultArrangement();
|
||||
surfaceArrangement.Arrange(_devices);
|
||||
foreach (ArtemisDevice artemisDevice in _devices)
|
||||
artemisDevice.ApplyDefaultCategories();
|
||||
|
||||
SaveDevices();
|
||||
}
|
||||
|
||||
|
||||
@ -121,5 +121,11 @@ namespace Artemis.Core.Services
|
||||
/// <param name="nameAffix">Text to add after the name of the profile (separated by a dash)</param>
|
||||
/// <returns></returns>
|
||||
ProfileDescriptor ImportProfile(string json, ProfileModule profileModule, string nameAffix = "imported");
|
||||
|
||||
/// <summary>
|
||||
/// Adapts a given profile to the currently active devices
|
||||
/// </summary>
|
||||
/// <param name="profile">The profile to adapt</param>
|
||||
void AdaptProfile(Profile profile);
|
||||
}
|
||||
}
|
||||
@ -122,7 +122,7 @@ namespace Artemis.Core.Services
|
||||
ProfileEntity entity = _profileRepository.Get(module.ActiveProfile.EntityId);
|
||||
Profile profile = new(module, entity);
|
||||
InstantiateProfile(profile);
|
||||
|
||||
|
||||
module.ChangeActiveProfile(null, _rgbService.EnabledDevices);
|
||||
module.ChangeActiveProfile(profile, _rgbService.EnabledDevices);
|
||||
}
|
||||
@ -166,7 +166,6 @@ namespace Artemis.Core.Services
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void ClearActiveProfile(ProfileModule module)
|
||||
{
|
||||
module.ChangeActiveProfile(null, _rgbService.EnabledDevices);
|
||||
@ -294,13 +293,21 @@ namespace Artemis.Core.Services
|
||||
return new ProfileDescriptor(profileModule, profileEntity);
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public void AdaptProfile(Profile profile)
|
||||
{
|
||||
List<ArtemisDevice> devices = _rgbService.EnabledDevices.ToList();
|
||||
foreach (Layer layer in profile.GetAllLayers())
|
||||
layer.Adapter.Adapt(devices);
|
||||
}
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void RgbServiceOnLedsChanged(object? sender, EventArgs e)
|
||||
{
|
||||
ActiveProfilesPopulateLeds();
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,13 @@
|
||||
namespace Artemis.Storage.Entities.Profile.AdaptionHints
|
||||
{
|
||||
public class CategoryAdaptionHintEntity : IAdaptionHintEntity
|
||||
{
|
||||
public int Category { get; set; }
|
||||
|
||||
public bool LimitAmount { get; set; }
|
||||
public int Skip { get; set; }
|
||||
public int Amount { get; set; }
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
namespace Artemis.Storage.Entities.Profile.AdaptionHints
|
||||
{
|
||||
public class DeviceAdaptionHintEntity : IAdaptionHintEntity
|
||||
{
|
||||
public int DeviceType { get; set; }
|
||||
|
||||
public bool LimitAmount { get; set; }
|
||||
public int Skip { get; set; }
|
||||
public int Amount { get; set; }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
namespace Artemis.Storage.Entities.Profile.AdaptionHints
|
||||
{
|
||||
public interface IAdaptionHintEntity
|
||||
{
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
namespace Artemis.Storage.Entities.Profile.AdaptionHints
|
||||
{
|
||||
public class KeyboardSectionAdaptionHintEntity : IAdaptionHintEntity
|
||||
{
|
||||
public int Section { get; set; }
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Artemis.Storage.Entities.Profile.Abstract;
|
||||
using Artemis.Storage.Entities.Profile.AdaptionHints;
|
||||
using LiteDB;
|
||||
|
||||
namespace Artemis.Storage.Entities.Profile
|
||||
@ -10,6 +11,7 @@ namespace Artemis.Storage.Entities.Profile
|
||||
public LayerEntity()
|
||||
{
|
||||
Leds = new List<LedEntity>();
|
||||
AdaptionHints = new List<IAdaptionHintEntity>();
|
||||
PropertyEntities = new List<PropertyEntity>();
|
||||
LayerEffects = new List<LayerEffectEntity>();
|
||||
ExpandedPropertyGroups = new List<string>();
|
||||
@ -20,6 +22,7 @@ namespace Artemis.Storage.Entities.Profile
|
||||
public bool Suspended { get; set; }
|
||||
|
||||
public List<LedEntity> Leds { get; set; }
|
||||
public List<IAdaptionHintEntity> AdaptionHints { get; set; }
|
||||
|
||||
[BsonRef("ProfileEntity")]
|
||||
public ProfileEntity Profile { get; set; }
|
||||
|
||||
@ -4,5 +4,7 @@
|
||||
{
|
||||
public string LedName { get; set; }
|
||||
public string DeviceIdentifier { get; set; }
|
||||
|
||||
public int? PhysicalLayout { get; set; }
|
||||
}
|
||||
}
|
||||
@ -8,8 +8,9 @@ namespace Artemis.Storage.Entities.Surface
|
||||
{
|
||||
InputIdentifiers = new List<DeviceInputIdentifierEntity>();
|
||||
InputMappings = new List<InputMappingEntity>();
|
||||
Categories = new List<int>();
|
||||
}
|
||||
|
||||
|
||||
public string Id { get; set; }
|
||||
public float X { get; set; }
|
||||
public float Y { get; set; }
|
||||
@ -27,7 +28,7 @@ namespace Artemis.Storage.Entities.Surface
|
||||
|
||||
public List<DeviceInputIdentifierEntity> InputIdentifiers { get; set; }
|
||||
public List<InputMappingEntity> InputMappings { get; set; }
|
||||
|
||||
public List<int> Categories { get; set; }
|
||||
}
|
||||
|
||||
public class InputMappingEntity
|
||||
|
||||
@ -12,6 +12,8 @@ using Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings.DirectDataBi
|
||||
using Artemis.UI.Screens.ProfileEditor.LayerProperties.LayerEffects;
|
||||
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline;
|
||||
using Artemis.UI.Screens.ProfileEditor.LayerProperties.Tree;
|
||||
using Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs;
|
||||
using Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints;
|
||||
using Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem;
|
||||
using Artemis.UI.Screens.ProfileEditor.Visualization;
|
||||
using Artemis.UI.Screens.ProfileEditor.Visualization.Tools;
|
||||
@ -59,6 +61,14 @@ namespace Artemis.UI.Ninject.Factories
|
||||
LayerViewModel LayerViewModel(ProfileElement layer);
|
||||
}
|
||||
|
||||
public interface ILayerHintVmFactory : IVmFactory
|
||||
{
|
||||
LayerHintsDialogViewModel LayerHintsDialogViewModel(Layer layer);
|
||||
CategoryAdaptionHintViewModel CategoryAdaptionHintViewModel(CategoryAdaptionHint adaptionHint);
|
||||
DeviceAdaptionHintViewModel DeviceAdaptionHintViewModel(DeviceAdaptionHint adaptionHint);
|
||||
KeyboardSectionAdaptionHintViewModel KeyboardSectionAdaptionHintViewModel(KeyboardSectionAdaptionHint adaptionHint);
|
||||
}
|
||||
|
||||
public interface IProfileLayerVmFactory : IVmFactory
|
||||
{
|
||||
ProfileLayerViewModel Create(Layer layer, PanZoomViewModel panZoomViewModel);
|
||||
|
||||
@ -169,6 +169,12 @@
|
||||
</Button>
|
||||
<Separator />
|
||||
|
||||
<Button Command="{s:Action AdaptActiveProfile}" ToolTip="Adapt the profile to the current surface">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="AutoFix" Margin="0 0 15 0" />
|
||||
<TextBlock>Adapt profile</TextBlock>
|
||||
</StackPanel>
|
||||
</Button>
|
||||
<Button Command="{s:Action ExportActiveProfile}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<materialDesign:PackIcon Kind="Upload" Margin="0 0 15 0" />
|
||||
|
||||
@ -209,6 +209,20 @@ namespace Artemis.UI.Screens.ProfileEditor
|
||||
SelectedProfile = copy;
|
||||
}
|
||||
|
||||
public async Task AdaptActiveProfile()
|
||||
{
|
||||
if (_profileEditorService.SelectedProfile == null)
|
||||
return;
|
||||
|
||||
if (!await DialogService.ShowConfirmDialog(
|
||||
"Adapt profile",
|
||||
"Are you sure you want to adapt the profile to your current surface? Layer assignments may change."
|
||||
))
|
||||
return;
|
||||
|
||||
_profileService.AdaptProfile(_profileEditorService.SelectedProfile);
|
||||
}
|
||||
|
||||
public async Task ExportActiveProfile()
|
||||
{
|
||||
await DialogService.ShowDialog<ProfileExportViewModel>(new Dictionary<string, object>
|
||||
|
||||
@ -0,0 +1,20 @@
|
||||
using Artemis.Core;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints
|
||||
{
|
||||
public abstract class AdaptionHintViewModel : Screen
|
||||
{
|
||||
protected AdaptionHintViewModel(IAdaptionHint adaptionHint)
|
||||
{
|
||||
AdaptionHint = adaptionHint;
|
||||
}
|
||||
|
||||
public IAdaptionHint AdaptionHint { get; }
|
||||
|
||||
public void Remove()
|
||||
{
|
||||
((LayerHintsDialogViewModel) Parent).RemoveAdaptionHint(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,78 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints.CategoryAdaptionHintView"
|
||||
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.ProfileEditor.ProfileTree.Dialogs.AdaptionHints"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:Converters="clr-namespace:Artemis.UI.Converters"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:CategoryAdaptionHintViewModel}">
|
||||
<UserControl.Resources>
|
||||
<Converters:InverseBooleanConverter x:Key="InverseBooleanConverter" />
|
||||
</UserControl.Resources>
|
||||
<materialDesign:Card Margin="0 5" Padding="10">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Grid.ColumnSpan="3" Margin="0 0 0 5">
|
||||
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}" Text="Category hint" />
|
||||
<TextBlock Style="{StaticResource MaterialDesignBody2TextBlock}" Text="Applies the layer to devices of a certain category" />
|
||||
</StackPanel>
|
||||
|
||||
<Button Grid.Row="0"
|
||||
Grid.Column="3"
|
||||
VerticalAlignment="Top"
|
||||
HorizontalAlignment="Right"
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
ToolTip="Remove hint"
|
||||
Command="{s:Action Remove}">
|
||||
<materialDesign:PackIcon Kind="Delete" />
|
||||
</Button>
|
||||
|
||||
<ComboBox Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Style="{StaticResource MaterialDesignFilledComboBox}"
|
||||
materialDesign:HintAssist.Hint="Category"
|
||||
Margin="0 0 5 0"
|
||||
SelectedValue="{Binding CategoryAdaptionHint.Category}"
|
||||
ItemsSource="{Binding Categories}"
|
||||
SelectedValuePath="Value"
|
||||
DisplayMemberPath="Description" />
|
||||
|
||||
<TextBox Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignFilledTextBox}"
|
||||
materialDesign:HintAssist.Hint="Skip"
|
||||
materialDesign:TextFieldAssist.SuffixText="device(s)"
|
||||
Margin="5 0"
|
||||
Text="{Binding CategoryAdaptionHint.Skip}" />
|
||||
|
||||
<TextBox Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Style="{StaticResource MaterialDesignFilledTextBox}"
|
||||
materialDesign:HintAssist.Hint="Take"
|
||||
materialDesign:TextFieldAssist.SuffixText="device(s)"
|
||||
IsEnabled="{Binding TakeAllDevices, Converter={StaticResource InverseBooleanConverter}}"
|
||||
Margin="5 0"
|
||||
Text="{Binding CategoryAdaptionHint.Amount}" />
|
||||
|
||||
<CheckBox Grid.Row="1"
|
||||
Grid.Column="3"
|
||||
Content="Take all devices"
|
||||
VerticalAlignment="Top"
|
||||
Margin="0 18 0 0"
|
||||
IsChecked="{Binding TakeAllDevices}" />
|
||||
</Grid>
|
||||
</materialDesign:Card>
|
||||
</UserControl>
|
||||
@ -0,0 +1,46 @@
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints
|
||||
{
|
||||
public class CategoryAdaptionHintViewModel : AdaptionHintViewModel
|
||||
{
|
||||
private bool _takeAllDevices;
|
||||
|
||||
/// <inheritdoc />
|
||||
public CategoryAdaptionHintViewModel(CategoryAdaptionHint adaptionHint) : base(adaptionHint)
|
||||
{
|
||||
CategoryAdaptionHint = adaptionHint;
|
||||
Categories = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(DeviceCategory)));
|
||||
}
|
||||
|
||||
public CategoryAdaptionHint CategoryAdaptionHint { get; }
|
||||
public BindableCollection<ValueDescription> Categories { get; }
|
||||
|
||||
public bool TakeAllDevices
|
||||
{
|
||||
get => _takeAllDevices;
|
||||
set => SetAndNotify(ref _takeAllDevices, value);
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
TakeAllDevices = !CategoryAdaptionHint.LimitAmount;
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnClose()
|
||||
{
|
||||
CategoryAdaptionHint.LimitAmount = !TakeAllDevices;
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,79 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints.DeviceAdaptionHintView"
|
||||
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.ProfileEditor.ProfileTree.Dialogs.AdaptionHints"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:converters="clr-namespace:Artemis.UI.Converters"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:DeviceAdaptionHintViewModel}">
|
||||
<UserControl.Resources>
|
||||
<converters:InverseBooleanConverter x:Key="InverseBooleanConverter" />
|
||||
</UserControl.Resources>
|
||||
<materialDesign:Card Margin="0 5" Padding="10">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Grid.ColumnSpan="3" Margin="0 0 0 5">
|
||||
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}" Text="Device type hint" />
|
||||
<TextBlock Style="{StaticResource MaterialDesignBody2TextBlock}" Text="Applies the layer to devices of a certain type" />
|
||||
</StackPanel>
|
||||
|
||||
<Button Grid.Row="0"
|
||||
Grid.Column="3"
|
||||
VerticalAlignment="Top"
|
||||
HorizontalAlignment="Right"
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
ToolTip="Remove hint"
|
||||
Command="{s:Action Remove}">
|
||||
<materialDesign:PackIcon Kind="Delete" />
|
||||
</Button>
|
||||
|
||||
<ComboBox Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Style="{StaticResource MaterialDesignFilledComboBox}"
|
||||
materialDesign:HintAssist.Hint="Device type"
|
||||
Margin="0 0 5 0"
|
||||
SelectedValue="{Binding DeviceAdaptionHint.DeviceType}"
|
||||
ItemsSource="{Binding DeviceTypes}"
|
||||
SelectedValuePath="Value"
|
||||
DisplayMemberPath="Description">
|
||||
</ComboBox>
|
||||
|
||||
<TextBox Grid.Row="1"
|
||||
Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignFilledTextBox}"
|
||||
materialDesign:HintAssist.Hint="Skip"
|
||||
materialDesign:TextFieldAssist.SuffixText="device(s)"
|
||||
Margin="5 0"
|
||||
Text="{Binding DeviceAdaptionHint.Skip}"/>
|
||||
|
||||
<TextBox Grid.Row="1"
|
||||
Grid.Column="2"
|
||||
Style="{StaticResource MaterialDesignFilledTextBox}"
|
||||
materialDesign:HintAssist.Hint="Take"
|
||||
materialDesign:TextFieldAssist.SuffixText="device(s)"
|
||||
IsEnabled="{Binding TakeAllDevices, Converter={StaticResource InverseBooleanConverter}}"
|
||||
Margin="5 0"
|
||||
Text="{Binding DeviceAdaptionHint.Amount}"/>
|
||||
|
||||
<CheckBox Grid.Row="1"
|
||||
Grid.Column="3"
|
||||
Content="Take all devices"
|
||||
VerticalAlignment="Top"
|
||||
Margin="0 18 0 0"
|
||||
IsChecked="{Binding TakeAllDevices}" />
|
||||
</Grid>
|
||||
</materialDesign:Card>
|
||||
</UserControl>
|
||||
@ -0,0 +1,47 @@
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared;
|
||||
using RGB.NET.Core;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints
|
||||
{
|
||||
public class DeviceAdaptionHintViewModel : AdaptionHintViewModel
|
||||
{
|
||||
private bool _takeAllDevices;
|
||||
|
||||
/// <inheritdoc />
|
||||
public DeviceAdaptionHintViewModel(DeviceAdaptionHint adaptionHint) : base(adaptionHint)
|
||||
{
|
||||
DeviceAdaptionHint = adaptionHint;
|
||||
DeviceTypes = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(RGBDeviceType)));
|
||||
}
|
||||
|
||||
public DeviceAdaptionHint DeviceAdaptionHint { get; }
|
||||
public BindableCollection<ValueDescription> DeviceTypes { get; }
|
||||
|
||||
public bool TakeAllDevices
|
||||
{
|
||||
get => _takeAllDevices;
|
||||
set => SetAndNotify(ref _takeAllDevices, value);
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
TakeAllDevices = !DeviceAdaptionHint.LimitAmount;
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnClose()
|
||||
{
|
||||
DeviceAdaptionHint.LimitAmount = !TakeAllDevices;
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,53 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints.KeyboardSectionAdaptionHintView"
|
||||
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.ProfileEditor.ProfileTree.Dialogs.AdaptionHints"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:KeyboardSectionAdaptionHintViewModel}">
|
||||
<materialDesign:Card Margin="0 5" Padding="10">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Grid.ColumnSpan="3" Margin="0 0 0 5">
|
||||
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}" Text="Keyboard section hint" />
|
||||
<TextBlock Style="{StaticResource MaterialDesignBody2TextBlock}" Text="Applies the layer to a section of all keyboards" />
|
||||
</StackPanel>
|
||||
|
||||
<Button Grid.Row="0"
|
||||
Grid.Column="3"
|
||||
VerticalAlignment="Top"
|
||||
HorizontalAlignment="Right"
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
ToolTip="Remove hint"
|
||||
Command="{s:Action Remove}">
|
||||
<materialDesign:PackIcon Kind="Delete" />
|
||||
</Button>
|
||||
|
||||
<ComboBox Grid.Row="1"
|
||||
Grid.Column="0"
|
||||
Style="{StaticResource MaterialDesignFilledComboBox}"
|
||||
materialDesign:HintAssist.Hint="Section"
|
||||
Margin="0 0 5 0"
|
||||
HorizontalAlignment="Left"
|
||||
Width="209"
|
||||
SelectedValue="{Binding KeyboardSectionAdaptionHint.Section}"
|
||||
ItemsSource="{Binding Sections}"
|
||||
SelectedValuePath="Value"
|
||||
DisplayMemberPath="Description">
|
||||
</ComboBox>
|
||||
</Grid>
|
||||
</materialDesign:Card>
|
||||
</UserControl>
|
||||
@ -0,0 +1,19 @@
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints
|
||||
{
|
||||
public class KeyboardSectionAdaptionHintViewModel : AdaptionHintViewModel
|
||||
{
|
||||
/// <inheritdoc />
|
||||
public KeyboardSectionAdaptionHintViewModel(KeyboardSectionAdaptionHint adaptionHint) : base(adaptionHint)
|
||||
{
|
||||
KeyboardSectionAdaptionHint = adaptionHint;
|
||||
Sections = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(KeyboardSection)));
|
||||
}
|
||||
|
||||
public KeyboardSectionAdaptionHint KeyboardSectionAdaptionHint { get; }
|
||||
public BindableCollection<ValueDescription> Sections { get; }
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,112 @@
|
||||
<mde:MaterialWindow x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.LayerHintsDialogView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
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:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:s="https://github.com/canton7/Stylet"
|
||||
xmlns:mde="clr-namespace:MaterialDesignExtensions.Controls;assembly=MaterialDesignExtensions"
|
||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||
xmlns:svgc="http://sharpvectors.codeplex.com/svgc/"
|
||||
xmlns:dialogs="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs"
|
||||
mc:Ignorable="d"
|
||||
Title="{Binding DisplayName}"
|
||||
TitleBarIcon="{svgc:SvgImage Source=/Resources/Images/Logo/bow-white.svg}"
|
||||
Foreground="{DynamicResource MaterialDesignBody}"
|
||||
Background="{DynamicResource MaterialDesignPaper}"
|
||||
FontFamily="pack://application:,,,/MaterialDesignThemes.Wpf;component/Resources/Roboto/#Roboto"
|
||||
UseLayoutRounding="True"
|
||||
FadeContentIfInactive="False"
|
||||
Width="800"
|
||||
Height="800"
|
||||
d:DesignHeight="800" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance dialogs:LayerHintsDialogViewModel}"
|
||||
Icon="/Resources/Images/Logo/bow.ico">
|
||||
<mde:MaterialWindow.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.PopupBox.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
|
||||
</ResourceDictionary>
|
||||
</mde:MaterialWindow.Resources>
|
||||
|
||||
<materialDesign:DialogHost IsTabStop="False"
|
||||
Focusable="False"
|
||||
Identifier="DeviceDialog"
|
||||
DialogTheme="Inherit"
|
||||
SnackbarMessageQueue="{Binding LayerHintsMessageQueue}">
|
||||
<DockPanel>
|
||||
<mde:AppBar Type="Dense"
|
||||
Title="{Binding Layer.Name}"
|
||||
ShowShadow="True"
|
||||
DockPanel.Dock="Top"
|
||||
Margin="-18 0 0 0">
|
||||
<mde:AppBar.AppIcon>
|
||||
<materialDesign:PackIcon Kind="AutoFix" Width="20" Height="28" />
|
||||
</mde:AppBar.AppIcon>
|
||||
</mde:AppBar>
|
||||
|
||||
<Grid Margin="15">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="*" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Row="0" Style="{StaticResource MaterialDesignHeadline6TextBlock}">
|
||||
Introduction
|
||||
</TextBlock>
|
||||
<TextBlock Grid.Row="1" Style="{StaticResource MaterialDesignTextBlock}" TextWrapping="Wrap">
|
||||
In this window you can tell Artemis how this layer should be adapted when the profile is applied to a different set of devices by providing so-called adaption hints.
|
||||
<LineBreak />
|
||||
When sharing your profile with other people good hints help them import your profile without the need for manual adjustments.
|
||||
</TextBlock>
|
||||
|
||||
<TextBlock Grid.Row="2" Style="{StaticResource MaterialDesignHeadline6TextBlock}" Margin="0 25 0 0">
|
||||
Adaption hints
|
||||
</TextBlock>
|
||||
<ScrollViewer Grid.Row="3">
|
||||
<ItemsControl ItemsSource="{Binding Items}" Margin="0 0 10 0">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<materialDesign:TransitioningContent OpeningEffect="{materialDesign:TransitionEffect SlideInFromLeft}"
|
||||
OpeningEffectsOffset="{materialDesign:IndexedItemOffsetMultiplier 0:0:0.05}">
|
||||
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
|
||||
</materialDesign:TransitioningContent>
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</ScrollViewer>
|
||||
|
||||
<!-- Buttons -->
|
||||
<Grid Grid.Row="4">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Button Grid.Column="0"
|
||||
Style="{StaticResource MaterialDesignOutlinedButton}"
|
||||
Margin="0 8 8 0"
|
||||
Command="{s:Action AutoDetermineHints}"
|
||||
ToolTip="Attempt to automatically determine relevant hint(s) for this layer">
|
||||
AUTO-DETERMINE HINTS
|
||||
</Button>
|
||||
|
||||
<materialDesign:PopupBox Grid.Column="1"
|
||||
Style="{StaticResource MaterialDesignMultiFloatingActionAccentPopupBox}"
|
||||
ToolTip="Add a new hint"
|
||||
HorizontalAlignment="Right"
|
||||
Margin="0 5 0 0">
|
||||
<StackPanel>
|
||||
<Button ToolTip="Add a category hint" Content="{materialDesign:PackIcon Kind=Desk, Size=20}" Command="{s:Action AddCategoryHint}" />
|
||||
<Button ToolTip="Add a device type hint" Content="{materialDesign:PackIcon Kind=Devices, Size=20}" Command="{s:Action AddDeviceHint}" />
|
||||
<Button ToolTip="Add a keyboard-section hint" Content="{materialDesign:PackIcon Kind=Keyboard, Size=20}" Command="{s:Action AddKeyboardSectionHint}" />
|
||||
</StackPanel>
|
||||
</materialDesign:PopupBox>
|
||||
</Grid>
|
||||
</Grid>
|
||||
</DockPanel>
|
||||
</materialDesign:DialogHost>
|
||||
</mde:MaterialWindow>
|
||||
@ -0,0 +1,114 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs
|
||||
{
|
||||
public class LayerHintsDialogViewModel : Conductor<AdaptionHintViewModel>.Collection.AllActive
|
||||
{
|
||||
private readonly IRgbService _rgbService;
|
||||
private readonly ILayerHintVmFactory _vmFactory;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private SnackbarMessageQueue _layerHintsMessageQueue;
|
||||
|
||||
public LayerHintsDialogViewModel(Layer layer, IRgbService rgbService, ILayerHintVmFactory vmFactory, IProfileEditorService profileEditorService)
|
||||
{
|
||||
_rgbService = rgbService;
|
||||
_vmFactory = vmFactory;
|
||||
_profileEditorService = profileEditorService;
|
||||
|
||||
Layer = layer;
|
||||
DisplayName = "Layer hints | Artemis";
|
||||
}
|
||||
|
||||
public Layer Layer { get; }
|
||||
|
||||
public SnackbarMessageQueue LayerHintsMessageQueue
|
||||
{
|
||||
get => _layerHintsMessageQueue;
|
||||
set => SetAndNotify(ref _layerHintsMessageQueue, value);
|
||||
}
|
||||
|
||||
public void AutoDetermineHints()
|
||||
{
|
||||
List<IAdaptionHint> newHints = Layer.Adapter.DetermineHints(_rgbService.EnabledDevices);
|
||||
CreateHintViewModels(newHints);
|
||||
}
|
||||
|
||||
public void AddCategoryHint()
|
||||
{
|
||||
CategoryAdaptionHint hint = new();
|
||||
Layer.Adapter.AdaptionHints.Add(hint);
|
||||
Items.Add(_vmFactory.CategoryAdaptionHintViewModel(hint));
|
||||
}
|
||||
|
||||
public void AddDeviceHint()
|
||||
{
|
||||
DeviceAdaptionHint hint = new();
|
||||
Layer.Adapter.AdaptionHints.Add(hint);
|
||||
Items.Add(_vmFactory.DeviceAdaptionHintViewModel(hint));
|
||||
}
|
||||
|
||||
public void AddKeyboardSectionHint()
|
||||
{
|
||||
KeyboardSectionAdaptionHint hint = new();
|
||||
Layer.Adapter.AdaptionHints.Add(hint);
|
||||
Items.Add(_vmFactory.KeyboardSectionAdaptionHintViewModel(hint));
|
||||
}
|
||||
|
||||
public void RemoveAdaptionHint(AdaptionHintViewModel adaptionHintViewModel)
|
||||
{
|
||||
Layer.Adapter.AdaptionHints.Remove(adaptionHintViewModel.AdaptionHint);
|
||||
Items.Remove(adaptionHintViewModel);
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
LayerHintsMessageQueue = new SnackbarMessageQueue(TimeSpan.FromSeconds(5));
|
||||
CreateHintViewModels(Layer.Adapter.AdaptionHints);
|
||||
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
#region Overrides of AllActive
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnClose()
|
||||
{
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#endregion
|
||||
|
||||
private void CreateHintViewModels(List<IAdaptionHint> hints)
|
||||
{
|
||||
foreach (IAdaptionHint adapterAdaptionHint in hints)
|
||||
{
|
||||
switch (adapterAdaptionHint)
|
||||
{
|
||||
case CategoryAdaptionHint categoryAdaptionHint:
|
||||
Items.Add(_vmFactory.CategoryAdaptionHintViewModel(categoryAdaptionHint));
|
||||
break;
|
||||
case DeviceAdaptionHint deviceAdaptionHint:
|
||||
Items.Add(_vmFactory.DeviceAdaptionHintViewModel(deviceAdaptionHint));
|
||||
break;
|
||||
case KeyboardSectionAdaptionHint keyboardSectionAdaptionHint:
|
||||
Items.Add(_vmFactory.KeyboardSectionAdaptionHintViewModel(keyboardSectionAdaptionHint));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -35,6 +35,12 @@
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem Header="View adaption hints" Command="{s:Action OpenAdaptionHints}">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="AutoFix" />
|
||||
</MenuItem.Icon>
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem Header="Rename" Command="{s:Action RenameElement}" InputGestureText="F2">
|
||||
<MenuItem.Icon>
|
||||
<materialDesign:PackIcon Kind="RenameBox" />
|
||||
|
||||
@ -2,19 +2,32 @@
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
|
||||
{
|
||||
public class LayerViewModel : TreeItemViewModel
|
||||
{
|
||||
private readonly IWindowManager _windowManager;
|
||||
private ILayerHintVmFactory _vmFactory;
|
||||
|
||||
public LayerViewModel(ProfileElement layer,
|
||||
IRgbService rgbService,
|
||||
IProfileEditorService profileEditorService,
|
||||
IDialogService dialogService,
|
||||
IProfileTreeVmFactory profileTreeVmFactory,
|
||||
ILayerBrushService layerBrushService) :
|
||||
ILayerBrushService layerBrushService,
|
||||
IWindowManager windowManager,
|
||||
ILayerHintVmFactory vmFactory) :
|
||||
base(layer, rgbService, profileEditorService, dialogService, profileTreeVmFactory, layerBrushService)
|
||||
{
|
||||
_windowManager = windowManager;
|
||||
_vmFactory = vmFactory;
|
||||
}
|
||||
|
||||
public void OpenAdaptionHints()
|
||||
{
|
||||
_windowManager.ShowDialog(_vmFactory.LayerHintsDialogViewModel(Layer));
|
||||
}
|
||||
|
||||
public Layer Layer => ProfileElement as Layer;
|
||||
|
||||
@ -21,7 +21,41 @@
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<StackPanel Grid.Row="0">
|
||||
<Grid>
|
||||
<!-- Layout -->
|
||||
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}">
|
||||
Categories
|
||||
</TextBlock>
|
||||
<TextBlock Style="{StaticResource MaterialDesignCaptionTextBlock}"
|
||||
Foreground="{DynamicResource MaterialDesignBodyLight}"
|
||||
TextWrapping="Wrap"
|
||||
TextAlignment="Justify">
|
||||
Artemis uses categories to determine where the layers of imported profiles are applied to. <LineBreak/>
|
||||
You can hover over a category for a more detailed description.
|
||||
</TextBlock>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<CheckBox Style="{StaticResource MaterialDesignFilterChipOutlineCheckBox}"
|
||||
IsChecked="{Binding HasDeskCategory}"
|
||||
ToolTip="A device acting as desk ornamentation such as a LED strip"
|
||||
Content="Desk" />
|
||||
<CheckBox Style="{StaticResource MaterialDesignFilterChipOutlineCheckBox}"
|
||||
IsChecked="{Binding HasMonitorCategory}"
|
||||
ToolTip="A device attached to the monitor such as ambilight LEDs"
|
||||
Content="Monitor" />
|
||||
<CheckBox Style="{StaticResource MaterialDesignFilterChipOutlineCheckBox}"
|
||||
ToolTip="A device inside your computer case"
|
||||
IsChecked="{Binding HasCaseCategory}"
|
||||
Content="Case" />
|
||||
<CheckBox Style="{StaticResource MaterialDesignFilterChipOutlineCheckBox}"
|
||||
IsChecked="{Binding HasRoomCategory}"
|
||||
ToolTip="A device elsewhere in the room"
|
||||
Content="Room" />
|
||||
<CheckBox Style="{StaticResource MaterialDesignFilterChipOutlineCheckBox}"
|
||||
IsChecked="{Binding HasPeripheralsCategory}"
|
||||
ToolTip="A peripheral such as a mouse or keyboard"
|
||||
Content="Peripheral" />
|
||||
</StackPanel>
|
||||
|
||||
<Grid Margin="0 25">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="40" />
|
||||
@ -157,7 +191,7 @@
|
||||
</Grid>
|
||||
|
||||
<!-- Layout -->
|
||||
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}" Margin="0 25 0 0">
|
||||
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}">
|
||||
Custom layout
|
||||
</TextBlock>
|
||||
<TextBlock Style="{StaticResource MaterialDesignCaptionTextBlock}"
|
||||
|
||||
@ -22,6 +22,7 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs
|
||||
private SKColor _currentColor;
|
||||
private bool _displayOnDevices;
|
||||
private float _greenScale;
|
||||
private List<DeviceCategory> _categories;
|
||||
private float _initialBlueScale;
|
||||
private float _initialGreenScale;
|
||||
private float _initialRedScale;
|
||||
@ -100,13 +101,45 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs
|
||||
get => _displayOnDevices;
|
||||
set => SetAndNotify(ref _displayOnDevices, value);
|
||||
}
|
||||
|
||||
// This solution won't scale well but I don't expect there to be many more categories.
|
||||
// If for some reason there will be, dynamically creating a view model per category may be more appropriate
|
||||
public bool HasDeskCategory
|
||||
{
|
||||
get => GetCategory(DeviceCategory.Desk);
|
||||
set => SetCategory(DeviceCategory.Desk, value);
|
||||
}
|
||||
|
||||
public bool HasMonitorCategory
|
||||
{
|
||||
get => GetCategory(DeviceCategory.Monitor);
|
||||
set => SetCategory(DeviceCategory.Monitor, value);
|
||||
}
|
||||
|
||||
public bool HasCaseCategory
|
||||
{
|
||||
get => GetCategory(DeviceCategory.Case);
|
||||
set => SetCategory(DeviceCategory.Case, value);
|
||||
}
|
||||
|
||||
public bool HasRoomCategory
|
||||
{
|
||||
get => GetCategory(DeviceCategory.Room);
|
||||
set => SetCategory(DeviceCategory.Room, value);
|
||||
}
|
||||
|
||||
public bool HasPeripheralsCategory
|
||||
{
|
||||
get => GetCategory(DeviceCategory.Peripherals);
|
||||
set => SetCategory(DeviceCategory.Peripherals, value);
|
||||
}
|
||||
|
||||
public void ApplyScaling()
|
||||
{
|
||||
Device.RedScale = RedScale / 100f;
|
||||
Device.GreenScale = GreenScale / 100f;
|
||||
Device.BlueScale = BlueScale / 100f;
|
||||
|
||||
|
||||
_rgbService.Surface.Update(true);
|
||||
}
|
||||
|
||||
@ -151,6 +184,10 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs
|
||||
Device.RedScale = RedScale / 100f;
|
||||
Device.GreenScale = GreenScale / 100f;
|
||||
Device.BlueScale = BlueScale / 100f;
|
||||
Device.Categories.Clear();
|
||||
foreach (DeviceCategory deviceCategory in _categories)
|
||||
Device.Categories.Add(deviceCategory);
|
||||
|
||||
_rgbService.SaveDevice(Device);
|
||||
|
||||
_coreService.ModuleRenderingDisabled = false;
|
||||
@ -158,6 +195,12 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs
|
||||
|
||||
public void Reset()
|
||||
{
|
||||
HasDeskCategory = Device.Categories.Contains(DeviceCategory.Desk);
|
||||
HasMonitorCategory = Device.Categories.Contains(DeviceCategory.Monitor);
|
||||
HasCaseCategory = Device.Categories.Contains(DeviceCategory.Case);
|
||||
HasRoomCategory = Device.Categories.Contains(DeviceCategory.Room);
|
||||
HasPeripheralsCategory = Device.Categories.Contains(DeviceCategory.Peripherals);
|
||||
|
||||
Device.RedScale = _initialRedScale;
|
||||
Device.GreenScale = _initialGreenScale;
|
||||
Device.BlueScale = _initialBlueScale;
|
||||
@ -176,6 +219,7 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs
|
||||
_initialRedScale = Device.RedScale;
|
||||
_initialGreenScale = Device.GreenScale;
|
||||
_initialBlueScale = Device.BlueScale;
|
||||
_categories = new List<DeviceCategory>(Device.Categories);
|
||||
CurrentColor = SKColors.White;
|
||||
|
||||
_coreService.FrameRendering += OnFrameRendering;
|
||||
@ -192,6 +236,21 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs
|
||||
base.OnDeactivate();
|
||||
}
|
||||
|
||||
private bool GetCategory(DeviceCategory category)
|
||||
{
|
||||
return _categories.Contains(category);
|
||||
}
|
||||
|
||||
private void SetCategory(DeviceCategory category, bool value)
|
||||
{
|
||||
if (value && !_categories.Contains(category))
|
||||
_categories.Add(category);
|
||||
else
|
||||
_categories.Remove(category);
|
||||
|
||||
NotifyOfPropertyChange($"Has{category}Category");
|
||||
}
|
||||
|
||||
#region Event handlers
|
||||
|
||||
private void DeviceOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user