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

Merge pull request #815 from Artemis-RGB/development

Adaption hints - Added more hints and sections
This commit is contained in:
RobertBeekman 2023-09-10 12:00:15 +02:00 committed by GitHub
commit 888ed3743e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
21 changed files with 433 additions and 62 deletions

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.ComponentModel;
using System.Linq; using System.Linq;
using Artemis.Storage.Entities.Profile.AdaptionHints; using Artemis.Storage.Entities.Profile.AdaptionHints;
using RGB.NET.Core; using RGB.NET.Core;
@ -15,7 +16,12 @@ public class KeyboardSectionAdaptionHint : CorePropertyChanged, IAdaptionHint
{ {
{KeyboardSection.MacroKeys, Enum.GetValues<LedId>().Where(l => l >= LedId.Keyboard_Programmable1 && l <= LedId.Keyboard_Programmable32).ToList()}, {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.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()} {KeyboardSection.Extra, Enum.GetValues<LedId>().Where(l => l >= LedId.Keyboard_Custom1 && l <= LedId.Keyboard_Custom64).ToList()},
{KeyboardSection.FunctionKeys, Enum.GetValues<LedId>().Where(l => l >= LedId.Keyboard_F1 && l <= LedId.Keyboard_F12).ToList()},
{KeyboardSection.NumberKeys, Enum.GetValues<LedId>().Where(l => l >= LedId.Keyboard_1 && l <= LedId.Keyboard_0).ToList()},
{KeyboardSection.NumPad, Enum.GetValues<LedId>().Where(l => l >= LedId.Keyboard_NumLock && l <= LedId.Keyboard_NumPeriodAndDelete).ToList()},
{KeyboardSection.ArrowKeys, Enum.GetValues<LedId>().Where(l => l >= LedId.Keyboard_PageDown && l <= LedId.Keyboard_ArrowRight).ToList()},
{KeyboardSection.MediaKeys, Enum.GetValues<LedId>().Where(l => l >= LedId.Keyboard_MediaMute && l <= LedId.Keyboard_MediaNextTrack).ToList()},
}; };
private KeyboardSection _section; private KeyboardSection _section;
@ -46,6 +52,12 @@ public class KeyboardSectionAdaptionHint : CorePropertyChanged, IAdaptionHint
/// <inheritdoc /> /// <inheritdoc />
public void Apply(Layer layer, List<ArtemisDevice> devices) public void Apply(Layer layer, List<ArtemisDevice> devices)
{ {
if (Section == KeyboardSection.Movement)
{
ApplyMovement(layer, devices);
return;
}
// Only keyboards should have the LEDs we care about // Only keyboards should have the LEDs we care about
foreach (ArtemisDevice keyboard in devices.Where(d => d.DeviceType == RGBDeviceType.Keyboard)) foreach (ArtemisDevice keyboard in devices.Where(d => d.DeviceType == RGBDeviceType.Keyboard))
{ {
@ -54,6 +66,26 @@ public class KeyboardSectionAdaptionHint : CorePropertyChanged, IAdaptionHint
} }
} }
private void ApplyMovement(Layer layer, List<ArtemisDevice> devices)
{
// Only keyboards should have the LEDs we care about
foreach (ArtemisDevice keyboard in devices.Where(d => d.DeviceType == RGBDeviceType.Keyboard))
{
ArtemisLed? qLed = keyboard.Leds.FirstOrDefault(l => l.RgbLed.Id == LedId.Keyboard_Q);
ArtemisLed? aLed = keyboard.Leds.FirstOrDefault(l => l.RgbLed.Id == LedId.Keyboard_A);
if (qLed == null || aLed == null)
continue;
// AZERTY keyboards will have their A above their Q
bool isAzerty = aLed.Rectangle.MidX < qLed.Rectangle.MidX;
if (isAzerty)
layer.AddLeds(keyboard.Leds.Where(l => l.RgbLed.Id is LedId.Keyboard_Z or LedId.Keyboard_Q or LedId.Keyboard_S or LedId.Keyboard_D));
else
layer.AddLeds(keyboard.Leds.Where(l => l.RgbLed.Id is LedId.Keyboard_W or LedId.Keyboard_A or LedId.Keyboard_S or LedId.Keyboard_D));
}
}
/// <inheritdoc /> /// <inheritdoc />
public IAdaptionHintEntity GetEntry() public IAdaptionHintEntity GetEntry()
{ {
@ -77,15 +109,45 @@ public enum KeyboardSection
/// <summary> /// <summary>
/// A region containing the macro keys of a keyboard /// A region containing the macro keys of a keyboard
/// </summary> /// </summary>
MacroKeys, [Description("Macro Keys")] MacroKeys,
/// <summary> /// <summary>
/// A region containing the LED strips of a keyboard /// A region containing the LED strips of a keyboard
/// </summary> /// </summary>
LedStrips, [Description("LED Strips")] LedStrips,
/// <summary> /// <summary>
/// A region containing extra non-standard LEDs of a keyboard /// A region containing the extra non-standard LEDs of a keyboard
/// </summary> /// </summary>
Extra [Description("Extra LEDs")] Extra,
/// <summary>
/// A region containing the movement keys of a keyboard (WASD for QWERTY and ZQSD for AZERTY)
/// </summary>
[Description("Movement (WASD/ZQSD)")] Movement,
/// <summary>
/// A region containing the F-keys of a keyboard
/// </summary>
[Description("F-keys")] FunctionKeys,
/// <summary>
/// A region containing the numeric keys of a keyboard
/// </summary>
[Description("Numeric keys")] NumberKeys,
/// <summary>
/// A region containing the Numpad of a keyboard
/// </summary>
[Description("Numpad")] NumPad,
/// <summary>
/// A region containing the arrow keys of a keyboard
/// </summary>
[Description("Arrow keys")] ArrowKeys,
/// <summary>
/// A region containing the media keys of a keyboard
/// </summary>
[Description("Media keys")] MediaKeys
} }

View File

@ -0,0 +1,102 @@
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 single LED of one or more devices
/// </summary>
public class SingleLedAdaptionHint : CorePropertyChanged, IAdaptionHint
{
private LedId _ledId;
private int _skip;
private bool _limitAmount;
private int _amount;
/// <summary>
/// Creates a new instance of the <see cref="SingleLedAdaptionHint" /> class
/// </summary>
public SingleLedAdaptionHint()
{
}
internal SingleLedAdaptionHint(SingleLedAdaptionHintEntity entity)
{
LedId = (LedId) entity.LedId;
Skip = entity.Skip;
LimitAmount = entity.LimitAmount;
Amount = entity.Amount;
}
/// <summary>
/// Gets or sets the LED ID to apply to.
/// </summary>
public LedId LedId
{
get => _ledId;
set => SetAndNotify(ref _ledId, value);
}
/// <summary>
/// Gets or sets the amount of devices to skip
/// </summary>
public int Skip
{
get => _skip;
set => SetAndNotify(ref _skip, value);
}
/// <summary>
/// Gets or sets a boolean indicating whether a limited amount of devices should be used
/// </summary>
public bool LimitAmount
{
get => _limitAmount;
set => SetAndNotify(ref _limitAmount, value);
}
/// <summary>
/// Gets or sets the amount of devices to limit to if <see cref="LimitAmount" /> is <see langword="true" />
/// </summary>
public int Amount
{
get => _amount;
set => SetAndNotify(ref _amount, value);
}
#region Implementation of IAdaptionHint
/// <inheritdoc />
public void Apply(Layer layer, List<ArtemisDevice> devices)
{
IEnumerable<ArtemisDevice> matches = devices
.Where(d => d.Leds.Any(l => l.RgbLed.Id == LedId))
.OrderBy(d => d.Rectangle.Top)
.ThenBy(d => d.Rectangle.Left)
.Skip(Skip);
if (LimitAmount)
matches = matches.Take(Amount);
foreach (ArtemisDevice artemisDevice in matches)
{
ArtemisLed led = artemisDevice.Leds.First(l => l.RgbLed.Id == LedId);
layer.AddLed(led);
}
}
/// <inheritdoc />
public IAdaptionHintEntity GetEntry()
{
return new SingleLedAdaptionHintEntity {Amount = Amount, LimitAmount = LimitAmount, Skip = Skip, LedId = (int) LedId};
}
/// <inheritdoc />
public override string ToString()
{
return $"Single LED adaption - {nameof(LedId)}: {LedId}, {nameof(Skip)}: {Skip}, {nameof(LimitAmount)}: {LimitAmount}, {nameof(Amount)}: {Amount}";
}
#endregion
}

View File

@ -111,6 +111,15 @@ public class LayerAdapter : IStorageModel
newHints.Add(hint); newHints.Add(hint);
} }
} }
// A single LED assignment is turned into a hint for one matching LED ID on the same device type
if (Layer.Leds.Count == 1)
{
ArtemisLed led = Layer.Leds.Single();
SingleLedAdaptionHint hint = new() {LedId = led.RgbLed.Id, Amount = 1, LimitAmount = true};
Add(hint);
newHints.Add(hint);
}
} }
return newHints; return newHints;
@ -184,6 +193,9 @@ public class LayerAdapter : IStorageModel
case KeyboardSectionAdaptionHintEntity entity: case KeyboardSectionAdaptionHintEntity entity:
Add(new KeyboardSectionAdaptionHint(entity)); Add(new KeyboardSectionAdaptionHint(entity));
break; break;
case SingleLedAdaptionHintEntity entity:
Add(new SingleLedAdaptionHint(entity));
break;
} }
} }
} }

View File

@ -0,0 +1,10 @@
namespace Artemis.Storage.Entities.Profile.AdaptionHints;
public class SingleLedAdaptionHintEntity : IAdaptionHintEntity
{
public int LedId { get; set; }
public bool LimitAmount { get; set; }
public int Skip { get; set; }
public int Amount { get; set; }
}

View File

@ -8,7 +8,7 @@
<ComboBox x:Name="ChildEnumComboBox" HorizontalAlignment="Stretch"> <ComboBox x:Name="ChildEnumComboBox" HorizontalAlignment="Stretch">
<ComboBox.ItemTemplate> <ComboBox.ItemTemplate>
<DataTemplate x:DataType="local:EnumComboBoxItem"> <DataTemplate x:DataType="local:EnumComboBoxItem">
<TextBlock Text="{CompiledBinding Value}" /> <TextBlock Text="{CompiledBinding Description}" />
</DataTemplate> </DataTemplate>
</ComboBox.ItemTemplate> </ComboBox.ItemTemplate>
</ComboBox> </ComboBox>

View File

@ -0,0 +1,45 @@
using System.Collections.Generic;
using Artemis.Core;
namespace Artemis.UI.Shared.Services.ProfileEditor.Commands;
/// <summary>
/// Represents a profile editor command that can be used to apply adaption hints to a layer.
/// </summary>
public class ApplyAdaptionHints : IProfileEditorCommand
{
private readonly Layer _layer;
private readonly List<ArtemisDevice> _devices;
private readonly List<ArtemisLed> _originalLeds;
/// <summary>
/// Creates a new instance of the <see cref="ApplyAdaptionHints" /> class.
/// </summary>
public ApplyAdaptionHints(Layer layer, List<ArtemisDevice> devices)
{
_layer = layer;
_devices = devices;
_originalLeds = new List<ArtemisLed>(_layer.Leds);
}
#region Implementation of IProfileEditorCommand
/// <inheritdoc />
public string DisplayName => "Apply adaption hints";
/// <inheritdoc />
public void Execute()
{
_layer.ClearLeds();
_layer.Adapter.Adapt(_devices);
}
/// <inheritdoc />
public void Undo()
{
_layer.ClearLeds();
_layer.AddLeds(_originalLeds);
}
#endregion
}

View File

@ -51,23 +51,4 @@
<ItemGroup> <ItemGroup>
<AvaloniaResource Include="Assets\**" /> <AvaloniaResource Include="Assets\**" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Compile Update="Screens\Workshop\Entries\Tabs\ProfileListView.axaml.cs">
<DependentUpon>ProfileListView.axaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Update="Screens\Workshop\Entries\Tabs\LayoutListView.axaml.cs">
<DependentUpon>LayoutListView.axaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Update="Screens\Workshop\Library\SubmissionDetailView.axaml.cs">
<DependentUpon>SubmissionsDetailView.axaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Screens\Workshop\Entries\Windows\MarkdownPreviewView.axaml" />
</ItemGroup>
</Project> </Project>

View File

@ -430,6 +430,7 @@ public interface ILayerHintVmFactory : IVmFactory
CategoryAdaptionHintViewModel CategoryAdaptionHintViewModel(Layer layer, CategoryAdaptionHint adaptionHint); CategoryAdaptionHintViewModel CategoryAdaptionHintViewModel(Layer layer, CategoryAdaptionHint adaptionHint);
DeviceAdaptionHintViewModel DeviceAdaptionHintViewModel(Layer layer, DeviceAdaptionHint adaptionHint); DeviceAdaptionHintViewModel DeviceAdaptionHintViewModel(Layer layer, DeviceAdaptionHint adaptionHint);
KeyboardSectionAdaptionHintViewModel KeyboardSectionAdaptionHintViewModel(Layer layer, KeyboardSectionAdaptionHint adaptionHint); KeyboardSectionAdaptionHintViewModel KeyboardSectionAdaptionHintViewModel(Layer layer, KeyboardSectionAdaptionHint adaptionHint);
SingleLedAdaptionHintViewModel SingleLedAdaptionHintViewModel(Layer layer, SingleLedAdaptionHint adaptionHint);
} }
public class LayerHintVmFactory : ILayerHintVmFactory public class LayerHintVmFactory : ILayerHintVmFactory
{ {
@ -454,6 +455,11 @@ public class LayerHintVmFactory : ILayerHintVmFactory
{ {
return _container.Resolve<KeyboardSectionAdaptionHintViewModel>(new object[] { layer, adaptionHint }); return _container.Resolve<KeyboardSectionAdaptionHintViewModel>(new object[] { layer, adaptionHint });
} }
public SingleLedAdaptionHintViewModel SingleLedAdaptionHintViewModel(Layer layer, SingleLedAdaptionHint adaptionHint)
{
return _container.Resolve<SingleLedAdaptionHintViewModel>(new object[] { layer, adaptionHint });
}
} }
public interface IScriptVmFactory : IVmFactory public interface IScriptVmFactory : IVmFactory

View File

@ -26,7 +26,7 @@
</Button> </Button>
<StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal" Spacing="5"> <StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal" Spacing="5">
<shared:EnumComboBox Value="{CompiledBinding CategoryAdaptionHint.Category}" Width="130" Margin="0 0 10 0" /> <shared:EnumComboBox Value="{CompiledBinding CategoryAdaptionHint.Category}" Width="200" Margin="0 0 10 0" />
<TextBlock VerticalAlignment="Center">Skip</TextBlock> <TextBlock VerticalAlignment="Center">Skip</TextBlock>
<controls:NumberBox HorizontalAlignment="Stretch" <controls:NumberBox HorizontalAlignment="Stretch"

View File

@ -26,7 +26,7 @@
</Button> </Button>
<StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal" Spacing="5"> <StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal" Spacing="5">
<shared:EnumComboBox Value="{CompiledBinding DeviceAdaptionHint.DeviceType}" Width="130" Margin="0 0 10 0" /> <shared:EnumComboBox Value="{CompiledBinding DeviceAdaptionHint.DeviceType}" Width="200" Margin="0 0 10 0" />
<TextBlock VerticalAlignment="Center">Skip</TextBlock> <TextBlock VerticalAlignment="Center">Skip</TextBlock>
<controls:NumberBox HorizontalAlignment="Stretch" <controls:NumberBox HorizontalAlignment="Stretch"

View File

@ -25,7 +25,7 @@
</Button> </Button>
<StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal" Spacing="5"> <StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal" Spacing="5">
<shared:EnumComboBox Value="{CompiledBinding KeyboardSectionAdaptionHint.Section}" Width="130" Margin="0 0 10 0" /> <shared:EnumComboBox Value="{CompiledBinding KeyboardSectionAdaptionHint.Section}" Width="200" Margin="0 0 10 0" />
</StackPanel> </StackPanel>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@ -0,0 +1,57 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:adaptionHints="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints.SingleLedAdaptionHintView"
x:DataType="adaptionHints:SingleLedAdaptionHintViewModel">
<Grid ColumnDefinitions="*,Auto" RowDefinitions="Auto,Auto">
<StackPanel Grid.ColumnSpan="2" Margin="0 0 0 5">
<TextBlock Classes="h5">Single LED hint</TextBlock>
<TextBlock Classes="subtitle">Applies the layer to a single LED of one or more devices</TextBlock>
</StackPanel>
<Button Grid.Row="0"
Grid.Column="1"
Classes="icon-button"
VerticalAlignment="Top"
HorizontalAlignment="Right"
ToolTip.Tip="Remove hint"
Command="{CompiledBinding Remove}">
<avalonia:MaterialIcon Kind="Delete" />
</Button>
<StackPanel Grid.Row="1" Grid.Column="0" Orientation="Horizontal" Spacing="5">
<controls:FAComboBox Width="200"
Margin="0 0 10 0"
ItemsSource="{CompiledBinding AdaptionLeds}"
SelectedItem="{CompiledBinding SelectedLed}"
DisplayMemberBinding="{CompiledBinding Description}"
IsEditable="True"
IsTextSearchEnabled="True"></controls:FAComboBox>
<TextBlock VerticalAlignment="Center">Skip</TextBlock>
<controls:NumberBox HorizontalAlignment="Stretch"
Value="{CompiledBinding SingleLedAdaptionHint.Skip}"
Minimum="0" />
<TextBlock VerticalAlignment="Center">device(s)</TextBlock>
<TextBlock VerticalAlignment="Center">Take</TextBlock>
<controls:NumberBox IsEnabled="{CompiledBinding SingleLedAdaptionHint.LimitAmount}"
HorizontalAlignment="Stretch"
Value="{CompiledBinding SingleLedAdaptionHint.Amount}"
Minimum="1" />
<TextBlock VerticalAlignment="Center">device(s)</TextBlock>
</StackPanel>
<CheckBox Grid.Row="1"
Grid.Column="1"
Content="Take all devices"
VerticalAlignment="Center"
HorizontalAlignment="Right"
IsChecked="{CompiledBinding !SingleLedAdaptionHint.LimitAmount}" />
</Grid>
</UserControl>

View File

@ -0,0 +1,13 @@
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints;
public partial class SingleLedAdaptionHintView : UserControl
{
public SingleLedAdaptionHintView()
{
InitializeComponent();
}
}

View File

@ -0,0 +1,53 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading.Tasks;
using Artemis.Core;
using ReactiveUI;
using RGB.NET.Core;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints;
public class SingleLedAdaptionHintViewModel : AdaptionHintViewModelBase
{
private List<AdaptionLed> _adaptionLeds;
private AdaptionLed? _selectedLed;
public SingleLedAdaptionHintViewModel(Layer layer, SingleLedAdaptionHint adaptionHint) : base(layer, adaptionHint)
{
SingleLedAdaptionHint = adaptionHint;
this.WhenAnyValue(vm => vm.SelectedLed).WhereNotNull().Subscribe(l => SingleLedAdaptionHint.LedId = l.Value);
Task.Run(() =>
{
AdaptionLeds = Enum.GetValues<LedId>().Select(l => new AdaptionLed(l)).ToList();
SelectedLed = AdaptionLeds.FirstOrDefault(l => l.Value == adaptionHint.LedId);
});
}
public List<AdaptionLed> AdaptionLeds
{
get => _adaptionLeds;
set => RaiseAndSetIfChanged(ref _adaptionLeds, value);
}
public AdaptionLed? SelectedLed
{
get => _selectedLed;
set => RaiseAndSetIfChanged(ref _selectedLed, value);
}
public SingleLedAdaptionHint SingleLedAdaptionHint { get; }
}
public class AdaptionLed
{
public AdaptionLed(LedId led)
{
Value = led;
Description = led.ToString();
}
public LedId Value { get; }
public string Description { get; }
}

View File

@ -34,37 +34,34 @@
</TextBlock> </TextBlock>
</Grid> </Grid>
<Border Grid.Row="1" Classes="card" Margin="0 15"> <Panel Grid.Row="1" Classes="card" Margin="0 15">
<Panel> <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Hidden" IsVisible="{CompiledBinding AdaptionHints.Count}">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Hidden" IsVisible="{CompiledBinding AdaptionHints.Count}"> <ItemsControl ItemsSource="{CompiledBinding AdaptionHints}" Classes="adaption-hints">
<ItemsControl ItemsSource="{CompiledBinding AdaptionHints}" Classes="adaption-hints"> <ItemsControl.ItemsPanel>
<ItemsControl.ItemsPanel> <ItemsPanelTemplate>
<ItemsPanelTemplate> <StackPanel Spacing="5" />
<StackPanel Spacing="10" /> </ItemsPanelTemplate>
</ItemsPanelTemplate> </ItemsControl.ItemsPanel>
</ItemsControl.ItemsPanel> <ItemsControl.ItemTemplate>
<ItemsControl.ItemTemplate> <DataTemplate>
<DataTemplate> <Border Classes="card-condensed">
<Border Classes="card-condensed"> <ContentControl Content="{CompiledBinding}"></ContentControl>
<ContentControl Content="{CompiledBinding}"></ContentControl> </Border>
</Border> </DataTemplate>
</DataTemplate> </ItemsControl.ItemTemplate>
</ItemsControl.ItemTemplate> </ItemsControl>
</ItemsControl> </ScrollViewer>
</ScrollViewer>
<StackPanel IsVisible="{CompiledBinding !AdaptionHints.Count}" VerticalAlignment="Center" HorizontalAlignment="Center"> <StackPanel IsVisible="{CompiledBinding !AdaptionHints.Count}" VerticalAlignment="Center" HorizontalAlignment="Center">
<avalonia:MaterialIcon Kind="AlertCircleOutline" HorizontalAlignment="Center" Width="48" Height="48" /> <avalonia:MaterialIcon Kind="AlertCircleOutline" HorizontalAlignment="Center" Width="48" Height="48" />
<TextBlock Classes="h4" TextAlignment="Center" TextWrapping="Wrap"> <TextBlock Classes="h4" TextAlignment="Center" TextWrapping="Wrap">
You haven't set up any adaption hints You haven't set up any adaption hints
</TextBlock> </TextBlock>
<TextBlock Classes="subtitle" TextAlignment="Center" TextWrapping="Wrap"> <TextBlock Classes="subtitle" TextAlignment="Center" TextWrapping="Wrap">
Artemis will attempt to directly map the LEDs of this layer to different surfaces but results may vary. Artemis will attempt to directly map the LEDs of this layer to different surfaces but results may vary.
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
</Panel> </Panel>
</Border>
<Grid Grid.Row="2" ColumnDefinitions="*,Auto"> <Grid Grid.Row="2" ColumnDefinitions="*,Auto">
<Button Grid.Row="0" Grid.Column="0" Command="{CompiledBinding AutoDetermineHints}">Auto-determine hints</Button> <Button Grid.Row="0" Grid.Column="0" Command="{CompiledBinding AutoDetermineHints}">Auto-determine hints</Button>
@ -87,6 +84,11 @@
<avalonia:MaterialIcon Kind="Keyboard" /> <avalonia:MaterialIcon Kind="Keyboard" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
<MenuItem Header="Single LED hint" Command="{CompiledBinding AddSingleLedHint}">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="LedVariantOn" />
</MenuItem.Icon>
</MenuItem>
</MenuFlyout> </MenuFlyout>
</DropDownButton.Flyout> </DropDownButton.Flyout>
Add hint Add hint

View File

@ -66,6 +66,12 @@ public class LayerHintsDialogViewModel : DialogViewModelBase<bool>
{ {
Layer.Adapter.Add(new KeyboardSectionAdaptionHint()); Layer.Adapter.Add(new KeyboardSectionAdaptionHint());
} }
public void AddSingleLedHint()
{
Layer.Adapter.Add(new SingleLedAdaptionHint());
}
public void RemoveAdaptionHint(IAdaptionHint hint) public void RemoveAdaptionHint(IAdaptionHint hint)
{ {
@ -79,6 +85,7 @@ public class LayerHintsDialogViewModel : DialogViewModelBase<bool>
CategoryAdaptionHint categoryAdaptionHint => _vmFactory.CategoryAdaptionHintViewModel(Layer, categoryAdaptionHint), CategoryAdaptionHint categoryAdaptionHint => _vmFactory.CategoryAdaptionHintViewModel(Layer, categoryAdaptionHint),
DeviceAdaptionHint deviceAdaptionHint => _vmFactory.DeviceAdaptionHintViewModel(Layer, deviceAdaptionHint), DeviceAdaptionHint deviceAdaptionHint => _vmFactory.DeviceAdaptionHintViewModel(Layer, deviceAdaptionHint),
KeyboardSectionAdaptionHint keyboardSectionAdaptionHint => _vmFactory.KeyboardSectionAdaptionHintViewModel(Layer, keyboardSectionAdaptionHint), KeyboardSectionAdaptionHint keyboardSectionAdaptionHint => _vmFactory.KeyboardSectionAdaptionHintViewModel(Layer, keyboardSectionAdaptionHint),
SingleLedAdaptionHint singleLedAdaptionHint => _vmFactory.SingleLedAdaptionHintViewModel(Layer, singleLedAdaptionHint),
_ => throw new ArgumentOutOfRangeException(nameof(hint)) _ => throw new ArgumentOutOfRangeException(nameof(hint))
}; };
} }

View File

@ -22,7 +22,7 @@ public class FolderTreeItemViewModel : TreeItemViewModel
IProfileEditorService profileEditorService, IProfileEditorService profileEditorService,
IRgbService rgbService, IRgbService rgbService,
IProfileEditorVmFactory profileEditorVmFactory) IProfileEditorVmFactory profileEditorVmFactory)
: base(parent, folder, windowService, profileEditorService, profileEditorVmFactory) : base(parent, folder, windowService, rgbService, profileEditorService, profileEditorVmFactory)
{ {
_rgbService = rgbService; _rgbService = rgbService;
Folder = folder; Folder = folder;

View File

@ -22,7 +22,7 @@ public class LayerTreeItemViewModel : TreeItemViewModel
IProfileEditorService profileEditorService, IProfileEditorService profileEditorService,
IRgbService rgbService, IRgbService rgbService,
IProfileEditorVmFactory profileEditorVmFactory) IProfileEditorVmFactory profileEditorVmFactory)
: base(parent, layer, windowService, profileEditorService, profileEditorVmFactory) : base(parent, layer, windowService, rgbService, profileEditorService, profileEditorVmFactory)
{ {
_rgbService = rgbService; _rgbService = rgbService;
Layer = layer; Layer = layer;

View File

@ -119,6 +119,11 @@
<avalonia:MaterialIcon Kind="Magic" /> <avalonia:MaterialIcon Kind="Magic" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
<MenuItem Header="Apply adaption hints" Command="{CompiledBinding ApplyAdaptionHints}">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="CogPlay" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="-" /> <MenuItem Header="-" />
<MenuItem Header="Duplicate" Command="{CompiledBinding Duplicate}" InputGesture="Ctrl+D"> <MenuItem Header="Duplicate" Command="{CompiledBinding Duplicate}" InputGesture="Ctrl+D">
<MenuItem.Icon> <MenuItem.Icon>

View File

@ -7,6 +7,7 @@ using System.Reactive.Disposables;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.DryIoc.Factories; using Artemis.UI.DryIoc.Factories;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.ProfileEditor; using Artemis.UI.Shared.Services.ProfileEditor;
@ -22,8 +23,8 @@ public class ProfileTreeViewModel : TreeItemViewModel
private ObservableAsPropertyHelper<bool>? _keyBindingsEnabled; private ObservableAsPropertyHelper<bool>? _keyBindingsEnabled;
private TreeItemViewModel? _selectedChild; private TreeItemViewModel? _selectedChild;
public ProfileTreeViewModel(IWindowService windowService, IProfileEditorService profileEditorService, IProfileEditorVmFactory profileEditorVmFactory) public ProfileTreeViewModel(IWindowService windowService, IRgbService rgbService, IProfileEditorService profileEditorService, IProfileEditorVmFactory profileEditorVmFactory)
: base(null, null, windowService, profileEditorService, profileEditorVmFactory) : base(null, null, windowService, rgbService, profileEditorService, profileEditorVmFactory)
{ {
this.WhenActivated(d => this.WhenActivated(d =>
{ {

View File

@ -5,8 +5,10 @@ using System.Linq;
using System.Reactive; using System.Reactive;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.DryIoc.Factories; using Artemis.UI.DryIoc.Factories;
using Artemis.UI.Extensions; using Artemis.UI.Extensions;
using Artemis.UI.Screens.ProfileEditor.ProfileTree.ContentDialogs; using Artemis.UI.Screens.ProfileEditor.ProfileTree.ContentDialogs;
@ -26,6 +28,7 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
{ {
private readonly IProfileEditorVmFactory _profileEditorVmFactory; private readonly IProfileEditorVmFactory _profileEditorVmFactory;
private readonly IWindowService _windowService; private readonly IWindowService _windowService;
private readonly IRgbService _rgbService;
protected readonly IProfileEditorService ProfileEditorService; protected readonly IProfileEditorService ProfileEditorService;
private bool _canPaste; private bool _canPaste;
private RenderProfileElement? _currentProfileElement; private RenderProfileElement? _currentProfileElement;
@ -38,11 +41,13 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
protected TreeItemViewModel(TreeItemViewModel? parent, protected TreeItemViewModel(TreeItemViewModel? parent,
ProfileElement? profileElement, ProfileElement? profileElement,
IWindowService windowService, IWindowService windowService,
IRgbService rgbService,
IProfileEditorService profileEditorService, IProfileEditorService profileEditorService,
IProfileEditorVmFactory profileEditorVmFactory) IProfileEditorVmFactory profileEditorVmFactory)
{ {
ProfileEditorService = profileEditorService; ProfileEditorService = profileEditorService;
_windowService = windowService; _windowService = windowService;
_rgbService = rgbService;
_profileEditorVmFactory = profileEditorVmFactory; _profileEditorVmFactory = profileEditorVmFactory;
Parent = parent; Parent = parent;
@ -51,6 +56,7 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
AddLayer = ReactiveCommand.Create(ExecuteAddLayer); AddLayer = ReactiveCommand.Create(ExecuteAddLayer);
AddFolder = ReactiveCommand.Create(ExecuteAddFolder); AddFolder = ReactiveCommand.Create(ExecuteAddFolder);
OpenAdaptionHints = ReactiveCommand.CreateFromTask(ExecuteOpenAdaptionHints, this.WhenAnyValue(vm => vm.ProfileElement).Select(p => p is Layer)); OpenAdaptionHints = ReactiveCommand.CreateFromTask(ExecuteOpenAdaptionHints, this.WhenAnyValue(vm => vm.ProfileElement).Select(p => p is Layer));
ApplyAdaptionHints = ReactiveCommand.Create(ExecuteApplyAdaptionHints, this.WhenAnyValue(vm => vm.ProfileElement).Select(p => p is Layer));
Rename = ReactiveCommand.CreateFromTask(ExecuteRename); Rename = ReactiveCommand.CreateFromTask(ExecuteRename);
Delete = ReactiveCommand.Create(ExecuteDelete); Delete = ReactiveCommand.Create(ExecuteDelete);
Duplicate = ReactiveCommand.CreateFromTask(ExecuteDuplicate); Duplicate = ReactiveCommand.CreateFromTask(ExecuteDuplicate);
@ -109,6 +115,7 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
public ReactiveCommand<Unit, Unit> AddLayer { get; } public ReactiveCommand<Unit, Unit> AddLayer { get; }
public ReactiveCommand<Unit, Unit> AddFolder { get; } public ReactiveCommand<Unit, Unit> AddFolder { get; }
public ReactiveCommand<Unit, Unit> OpenAdaptionHints { get; } public ReactiveCommand<Unit, Unit> OpenAdaptionHints { get; }
public ReactiveCommand<Unit, Unit> ApplyAdaptionHints { get; }
public ReactiveCommand<Unit, Unit> Rename { get; } public ReactiveCommand<Unit, Unit> Rename { get; }
public ReactiveCommand<Unit, Unit> Duplicate { get; } public ReactiveCommand<Unit, Unit> Duplicate { get; }
public ReactiveCommand<Unit, Unit> Copy { get; } public ReactiveCommand<Unit, Unit> Copy { get; }
@ -254,6 +261,14 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
await _windowService.ShowDialogAsync<LayerHintsDialogViewModel, bool>(layer); await _windowService.ShowDialogAsync<LayerHintsDialogViewModel, bool>(layer);
await ProfileEditorService.SaveProfileAsync(); await ProfileEditorService.SaveProfileAsync();
} }
private void ExecuteApplyAdaptionHints()
{
if (ProfileElement is not Layer layer)
return;
ProfileEditorService.ExecuteCommand(new ApplyAdaptionHints(layer, _rgbService.EnabledDevices.ToList()));
}
private async void UpdateCanPaste(bool isFlyoutOpen) private async void UpdateCanPaste(bool isFlyoutOpen)
{ {