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

Layer adapter hints - Ported UI

This commit is contained in:
Robert 2022-05-24 23:24:49 +02:00
parent 850346ccd2
commit 720bebaf35
23 changed files with 606 additions and 22 deletions

View File

@ -14,6 +14,7 @@
<entry key="Artemis.UI.Avalonia/Screens/Sidebar/Views/SidebarProfileConfigurationView.axaml" value="Artemis.UI.Avalonia/Artemis.UI.Avalonia.csproj" />
<entry key="Artemis.UI.Avalonia/Screens/SidebarView.axaml" value="Artemis.UI.Avalonia/Artemis.UI.Avalonia.csproj" />
<entry key="Artemis.UI.Avalonia/Views/MainWindow.axaml" value="Artemis.UI.Avalonia/Artemis.UI.Avalonia.csproj" />
<entry key="Artemis.UI.Shared/Controls/EnumComboBox.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI.Shared/Styles/Border.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI.Windows/App.axaml" value="Artemis.UI.Windows/Artemis.UI.Windows.csproj" />
<entry key="Artemis.UI/DefaultTypes/PropertyInput/ColorGradientPropertyInputView.axaml" value="Artemis.UI.Windows/Artemis.UI.Windows.csproj" />
@ -27,7 +28,12 @@
<entry key="Artemis.UI/Screens/Plugins/PluginFeatureView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/Plugins/PluginSettingsView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/CategoryAdaptionHintView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/DeviceAdaptionHintView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/AdaptionHints/KeyboardSectionAdaptionHintView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/LayerHintsDialogView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/LayerTreeItemView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/ProfileTreeView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Dialogs/AddEffectView.axaml" value="Artemis.UI.Windows/Artemis.UI.Windows.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/PropertiesView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
@ -40,6 +46,7 @@
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreeGroupView.axaml" value="Artemis.UI.Windows/Artemis.UI.Windows.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/TreePropertyView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Windows/EffectConfigurationWindowView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/StatusBar/StatusBarView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Tools/TransformToolView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/VisualEditorView.axaml" value="Artemis.UI.Windows/Artemis.UI.Windows.csproj" />
<entry key="Artemis.UI/Screens/ProfileEditor/ProfileEditorTitleBarView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
@ -47,6 +54,7 @@
<entry key="Artemis.UI/Screens/Root/SplashView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/Settings/Tabs/GeneralTabView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/Sidebar/ContentDialogs/SidebarCategoryEditView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/Sidebar/SidebarCategoryView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/Sidebar/SidebarProfileConfigurationView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
<entry key="Artemis.UI/Screens/Sidebar/SidebarView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />

View File

@ -0,0 +1,19 @@
using System;
namespace Artemis.Core;
/// <summary>
/// Provides data for layer adapter hint events.
/// </summary>
public class LayerAdapterHintEventArgs : EventArgs
{
internal LayerAdapterHintEventArgs(IAdaptionHint adaptionHint)
{
AdaptionHint = adaptionHint;
}
/// <summary>
/// Gets the layer adaption hint this event is related to
/// </summary>
public IAdaptionHint AdaptionHint { get; }
}

View File

@ -7,8 +7,13 @@ namespace Artemis.Core
/// <summary>
/// Represents a hint that adapts layers to a certain category of devices
/// </summary>
public class CategoryAdaptionHint : IAdaptionHint
public class CategoryAdaptionHint : CorePropertyChanged, IAdaptionHint
{
private DeviceCategory _category;
private int _skip;
private bool _limitAmount;
private int _amount;
/// <summary>
/// Creates a new instance of the <see cref="CategoryAdaptionHint" /> class
/// </summary>
@ -27,22 +32,38 @@ namespace Artemis.Core
/// <summary>
/// Gets or sets the category of devices LEDs will be applied to
/// </summary>
public DeviceCategory Category { get; set; }
public DeviceCategory Category
{
get => _category;
set => SetAndNotify(ref _category, value);
}
/// <summary>
/// Gets or sets the amount of devices to skip
/// </summary>
public int Skip { get; set; }
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; set; }
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; set; }
public int Amount
{
get => _amount;
set => SetAndNotify(ref _amount, value);
}
/// <inheritdoc />
public override string ToString()

View File

@ -8,8 +8,13 @@ namespace Artemis.Core
/// <summary>
/// Represents a hint that adapts layers to a certain type of devices
/// </summary>
public class DeviceAdaptionHint : IAdaptionHint
public class DeviceAdaptionHint : CorePropertyChanged, IAdaptionHint
{
private RGBDeviceType _deviceType;
private int _skip;
private bool _limitAmount;
private int _amount;
/// <summary>
/// Creates a new instance of the <see cref="DeviceAdaptionHint" /> class
/// </summary>
@ -28,22 +33,38 @@ namespace Artemis.Core
/// <summary>
/// Gets or sets the type of devices LEDs will be applied to
/// </summary>
public RGBDeviceType DeviceType { get; set; }
public RGBDeviceType DeviceType
{
get => _deviceType;
set => SetAndNotify(ref _deviceType, value);
}
/// <summary>
/// Gets or sets the amount of devices to skip
/// </summary>
public int Skip { get; set; }
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; set; }
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; set; }
public int Amount
{
get => _amount;
set => SetAndNotify(ref _amount, value);
}
#region Implementation of IAdaptionHint

View File

@ -9,7 +9,7 @@ namespace Artemis.Core
/// <summary>
/// Represents a hint that adapts layers to a certain region of keyboards
/// </summary>
public class KeyboardSectionAdaptionHint : IAdaptionHint
public class KeyboardSectionAdaptionHint : CorePropertyChanged, IAdaptionHint
{
private static readonly Dictionary<KeyboardSection, List<LedId>> RegionLedIds = new()
{
@ -18,6 +18,8 @@ namespace Artemis.Core
{KeyboardSection.Extra, Enum.GetValues<LedId>().Where(l => l >= LedId.Keyboard_Custom1 && l <= LedId.Keyboard_Custom64).ToList()}
};
private KeyboardSection _section;
/// <summary>
/// Creates a new instance of the <see cref="KeyboardSectionAdaptionHint" /> class
/// </summary>
@ -33,7 +35,11 @@ namespace Artemis.Core
/// <summary>
/// Gets or sets the section this hint will apply LEDs to
/// </summary>
public KeyboardSection Section { get; set; }
public KeyboardSection Section
{
get => _section;
set => SetAndNotify(ref _section, value);
}
#region Implementation of IAdaptionHint

View File

@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Artemis.Storage.Entities.Profile;
using Artemis.Storage.Entities.Profile.AdaptionHints;
@ -12,10 +13,13 @@ namespace Artemis.Core
/// </summary>
public class LayerAdapter : IStorageModel
{
private readonly List<IAdaptionHint> _adaptionHints;
internal LayerAdapter(Layer layer)
{
_adaptionHints = new List<IAdaptionHint>();
Layer = layer;
AdaptionHints = new List<IAdaptionHint>();
AdaptionHints = new ReadOnlyCollection<IAdaptionHint>(_adaptionHints);
}
/// <summary>
@ -26,7 +30,7 @@ namespace Artemis.Core
/// <summary>
/// Gets or sets a list containing the adaption hints used by this adapter
/// </summary>
public List<IAdaptionHint> AdaptionHints { get; set; }
public ReadOnlyCollection<IAdaptionHint> AdaptionHints { get; set; }
/// <summary>
/// Modifies the layer, adapting it to the provided <paramref name="devices" />
@ -73,7 +77,7 @@ namespace Artemis.Core
if (devices.All(DoesLayerCoverDevice))
{
DeviceAdaptionHint hint = new() {DeviceType = RGBDeviceType.All};
AdaptionHints.Add(hint);
Add(hint);
newHints.Add(hint);
}
else
@ -88,7 +92,7 @@ namespace Artemis.Core
if (DoesLayerCoverDevice(device))
{
DeviceAdaptionHint hint = new() {DeviceType = device.DeviceType};
AdaptionHints.Add(hint);
Add(hint);
newHints.Add(hint);
}
}
@ -103,7 +107,7 @@ namespace Artemis.Core
if (categoryDevices.Any() && categoryDevices.All(DoesLayerCoverDevice))
{
CategoryAdaptionHint hint = new() {Category = deviceCategory};
AdaptionHints.Add(hint);
Add(hint);
newHints.Add(hint);
}
}
@ -117,25 +121,57 @@ namespace Artemis.Core
return device.Leds.All(l => Layer.Leds.Contains(l));
}
/// <summary>
/// Adds an adaption hint to the adapter.
/// </summary>
/// <param name="adaptionHint">The adaption hint to add.</param>
public void Add(IAdaptionHint adaptionHint)
{
if (_adaptionHints.Contains(adaptionHint))
return;
_adaptionHints.Add(adaptionHint);
AdapterHintAdded?.Invoke(this, new LayerAdapterHintEventArgs(adaptionHint));
}
/// <summary>
/// Removes the first occurrence of a specific adaption hint from the adapter.
/// </summary>
/// <param name="adaptionHint">The adaption hint to remove.</param>
public void Remove(IAdaptionHint adaptionHint)
{
if (_adaptionHints.Remove(adaptionHint))
AdapterHintRemoved?.Invoke(this, new LayerAdapterHintEventArgs(adaptionHint));
}
/// <summary>
/// Removes all adaption hints from the adapter.
/// </summary>
public void Clear()
{
while (_adaptionHints.Any())
Remove(_adaptionHints.First());
}
#region Implementation of IStorageModel
/// <inheritdoc />
public void Load()
{
AdaptionHints.Clear();
_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));
Add(new DeviceAdaptionHint(entity));
break;
case CategoryAdaptionHintEntity entity:
AdaptionHints.Add(new CategoryAdaptionHint(entity));
Add(new CategoryAdaptionHint(entity));
break;
case KeyboardSectionAdaptionHintEntity entity:
AdaptionHints.Add(new KeyboardSectionAdaptionHint(entity));
Add(new KeyboardSectionAdaptionHint(entity));
break;
}
}
@ -149,5 +185,15 @@ namespace Artemis.Core
}
#endregion
/// <summary>
/// Occurs whenever a new adapter hint is added to the adapter.
/// </summary>
public event EventHandler<LayerAdapterHintEventArgs>? AdapterHintAdded;
/// <summary>
/// Occurs whenever an adapter hint is removed from the adapter.
/// </summary>
public event EventHandler<LayerAdapterHintEventArgs>? AdapterHintRemoved;
}
}

View File

@ -7,7 +7,7 @@
<ComboBox x:Name="EnumComboBox" HorizontalAlignment="Stretch">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding [0]}" />
<TextBlock Text="{Binding [1]}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>

View File

@ -7,6 +7,7 @@ using Artemis.UI.Screens.Plugins;
using Artemis.UI.Screens.ProfileEditor;
using Artemis.UI.Screens.ProfileEditor.DisplayCondition.ConditionTypes;
using Artemis.UI.Screens.ProfileEditor.ProfileTree;
using Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints;
using Artemis.UI.Screens.ProfileEditor.Properties;
using Artemis.UI.Screens.ProfileEditor.Properties.DataBinding;
using Artemis.UI.Screens.ProfileEditor.Properties.Timeline;
@ -115,3 +116,10 @@ public interface IConditionVmFactory : IVmFactory
StaticConditionViewModel StaticConditionViewModel(StaticCondition staticCondition);
EventConditionViewModel EventConditionViewModel(EventCondition eventCondition);
}
public interface ILayerHintVmFactory : IVmFactory
{
CategoryAdaptionHintViewModel CategoryAdaptionHintViewModel(CategoryAdaptionHint adaptionHint);
DeviceAdaptionHintViewModel DeviceAdaptionHintViewModel(DeviceAdaptionHint adaptionHint);
KeyboardSectionAdaptionHintViewModel KeyboardSectionAdaptionHintViewModel(KeyboardSectionAdaptionHint adaptionHint);
}

View File

@ -0,0 +1,22 @@
using System.Reactive;
using Artemis.Core;
using Artemis.UI.Shared;
using ReactiveUI;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints;
public abstract class AdaptionHintViewModelBase : ViewModelBase
{
protected AdaptionHintViewModelBase(IAdaptionHint adaptionHint)
{
AdaptionHint = adaptionHint;
Remove = ReactiveCommand.Create(ExecuteRemove);
}
public ReactiveCommand<Unit, Unit> Remove { get; }
public IAdaptionHint AdaptionHint { get; }
private void ExecuteRemove()
{
}
}

View File

@ -0,0 +1,52 @@
<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:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:adaptionHints="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints"
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.CategoryAdaptionHintView"
x:DataType="adaptionHints:CategoryAdaptionHintViewModel">
<Grid ColumnDefinitions="*,Auto" RowDefinitions="Auto,Auto">
<StackPanel Grid.ColumnSpan="2" Margin="0 0 0 5">
<TextBlock Classes="h5">Category hint</TextBlock>
<TextBlock Classes="subtitle">Applies the layer to devices of a certain category</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">
<shared:EnumComboBox Value="{CompiledBinding CategoryAdaptionHint.Category}" Width="130" Margin="0 0 10 0" />
<TextBlock VerticalAlignment="Center">Skip</TextBlock>
<controls:NumberBox HorizontalAlignment="Stretch"
Value="{CompiledBinding CategoryAdaptionHint.Skip}"
Minimum="0" />
<TextBlock VerticalAlignment="Center">device(s)</TextBlock>
<TextBlock VerticalAlignment="Center">Take</TextBlock>
<controls:NumberBox IsEnabled="{CompiledBinding CategoryAdaptionHint.LimitAmount}"
HorizontalAlignment="Stretch"
Value="{CompiledBinding CategoryAdaptionHint.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 !CategoryAdaptionHint.LimitAmount}" />
</Grid>
</UserControl>

View File

@ -0,0 +1,18 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints;
public partial class CategoryAdaptionHintView : UserControl
{
public CategoryAdaptionHintView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}

View File

@ -0,0 +1,13 @@
using Artemis.Core;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints;
public class CategoryAdaptionHintViewModel : AdaptionHintViewModelBase
{
public CategoryAdaptionHintViewModel(CategoryAdaptionHint adaptionHint) : base(adaptionHint)
{
CategoryAdaptionHint = adaptionHint;
}
public CategoryAdaptionHint CategoryAdaptionHint { get; }
}

View File

@ -0,0 +1,52 @@
<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.DeviceAdaptionHintView"
x:DataType="adaptionHints:DeviceAdaptionHintViewModel">
<Grid ColumnDefinitions="*,Auto" RowDefinitions="Auto,Auto">
<StackPanel Grid.ColumnSpan="2" Margin="0 0 0 5">
<TextBlock Classes="h5">Device type hint</TextBlock>
<TextBlock Classes="subtitle">Applies the layer to devices of a certain type</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">
<shared:EnumComboBox Value="{CompiledBinding DeviceAdaptionHint.DeviceType}" Width="130" Margin="0 0 10 0" />
<TextBlock VerticalAlignment="Center">Skip</TextBlock>
<controls:NumberBox HorizontalAlignment="Stretch"
Value="{CompiledBinding DeviceAdaptionHint.Skip}"
Minimum="0" />
<TextBlock VerticalAlignment="Center">device(s)</TextBlock>
<TextBlock VerticalAlignment="Center">Take</TextBlock>
<controls:NumberBox IsEnabled="{CompiledBinding DeviceAdaptionHint.LimitAmount}"
HorizontalAlignment="Stretch"
Value="{CompiledBinding DeviceAdaptionHint.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 !DeviceAdaptionHint.LimitAmount}" />
</Grid>
</UserControl>

View File

@ -0,0 +1,18 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints;
public partial class DeviceAdaptionHintView : UserControl
{
public DeviceAdaptionHintView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}

View File

@ -0,0 +1,13 @@
using Artemis.Core;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints;
public class DeviceAdaptionHintViewModel : AdaptionHintViewModelBase
{
public DeviceAdaptionHintViewModel(DeviceAdaptionHint adaptionHint) : base(adaptionHint)
{
DeviceAdaptionHint = adaptionHint;
}
public DeviceAdaptionHint DeviceAdaptionHint { get; }
}

View File

@ -0,0 +1,32 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns: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"
xmlns:adaptionHints="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints.KeyboardSectionAdaptionHintView"
x:DataType="adaptionHints:KeyboardSectionAdaptionHintViewModel">
<Grid ColumnDefinitions="*,Auto" RowDefinitions="Auto,Auto">
<StackPanel Grid.ColumnSpan="2" Margin="0 0 0 5">
<TextBlock Classes="h5">Keyboard section hint</TextBlock>
<TextBlock Classes="subtitle">Applies the layer to a section of all keyboards</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">
<shared:EnumComboBox Value="{CompiledBinding KeyboardSectionAdaptionHint.Section}" Width="130" Margin="0 0 10 0" />
</StackPanel>
</Grid>
</UserControl>

View File

@ -0,0 +1,18 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints;
public partial class KeyboardSectionAdaptionHintView : UserControl
{
public KeyboardSectionAdaptionHintView()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}

View File

@ -0,0 +1,13 @@
using Artemis.Core;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints;
public class KeyboardSectionAdaptionHintViewModel : AdaptionHintViewModelBase
{
public KeyboardSectionAdaptionHintViewModel(KeyboardSectionAdaptionHint adaptionHint) : base(adaptionHint)
{
KeyboardSectionAdaptionHint = adaptionHint;
}
public KeyboardSectionAdaptionHint KeyboardSectionAdaptionHint { get; }
}

View File

@ -0,0 +1,81 @@
<controls:CoreWindow 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:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:dialogs="clr-namespace:Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
mc:Ignorable="d"
x:Class="Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.LayerHintsDialogView"
x:DataType="dialogs:LayerHintsDialogViewModel"
Title="Artemis | Adaption hints"
Width="750"
Height="800">
<Grid Margin="15" RowDefinitions="Auto,*,Auto">
<Grid Grid.Row="0" ColumnDefinitions="*,Auto" RowDefinitions="Auto,Auto">
<StackPanel Grid.Row="0" Orientation="Horizontal">
<avalonia:MaterialIcon Kind="{CompiledBinding Layer.LayerBrush.Descriptor.Icon}" Width="24" Height="24" Margin="0 0 5 10"/>
<TextBlock Classes="h4" Text="{CompiledBinding Layer.Name}" TextWrapping="Wrap"/>
</StackPanel>
<controls:HyperlinkButton Grid.Row="0"
Grid.Column="1"
VerticalAlignment="Top"
NavigateUri="https://wiki.artemis-rgb.com/guides/user/profiles/layers/adaption-hints">
Learn more about adaption hints
</controls:HyperlinkButton>
<TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Classes="subtitle" TextWrapping="Wrap">
Add hints below to help decide where to place this layer when the profile is imported.
</TextBlock>
</Grid>
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Hidden" Margin="0 15">
<ItemsControl Items="{CompiledBinding AdaptionHints}" Classes="adaption-hints">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<StackPanel Spacing="10" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border Classes="card-condensed">
<ContentControl Content="{Binding}"></ContentControl>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</ScrollViewer>
<Grid Grid.Row="2" ColumnDefinitions="*,Auto">
<Button Grid.Row="0" Grid.Column="0" Command="{Binding AutoDetermineHints}">Auto-determine hints</Button>
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal" Spacing="5">
<controls:DropDownButton>
<controls:DropDownButton.Flyout>
<MenuFlyout Placement="Top">
<MenuItem Header="Category hint" Command="{Binding AddCategoryHint}">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="Desk" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Device type hint" Command="{Binding AddDeviceHint}">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="Devices" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Keyboard-section hint" Command="{Binding AddKeyboardSectionHint}">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="Keyboard" />
</MenuItem.Icon>
</MenuItem>
</MenuFlyout>
</controls:DropDownButton.Flyout>
Add hint
</controls:DropDownButton>
<Button Command="{Binding Finish}">Close</Button>
</StackPanel>
</Grid>
</Grid>
</controls:CoreWindow>

View File

@ -0,0 +1,22 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using FluentAvalonia.UI.Controls;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs;
public partial class LayerHintsDialogView : ReactiveCoreWindow<LayerHintsDialogViewModel>
{
public LayerHintsDialogView()
{
InitializeComponent();
#if DEBUG
this.AttachDevTools();
#endif
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}

View File

@ -0,0 +1,85 @@
using System;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive.Linq;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints;
using Artemis.UI.Shared;
using Avalonia.Controls.Mixins;
using DynamicData;
using ReactiveUI;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs;
public class LayerHintsDialogViewModel : DialogViewModelBase<bool>
{
private readonly IRgbService _rgbService;
private readonly ILayerHintVmFactory _vmFactory;
public LayerHintsDialogViewModel(Layer layer, IRgbService rgbService, ILayerHintVmFactory vmFactory)
{
_rgbService = rgbService;
_vmFactory = vmFactory;
Layer = layer;
AdaptionHints = new ObservableCollection<AdaptionHintViewModelBase>();
this.WhenActivated(d =>
{
Observable.FromEventPattern<LayerAdapterHintEventArgs>(x => layer.Adapter.AdapterHintAdded += x, x => layer.Adapter.AdapterHintAdded -= x)
.Subscribe(c => AdaptionHints.Add(CreateHintViewModel(c.EventArgs.AdaptionHint)))
.DisposeWith(d);
Observable.FromEventPattern<LayerAdapterHintEventArgs>(x => layer.Adapter.AdapterHintRemoved += x, x => layer.Adapter.AdapterHintRemoved -= x)
.Subscribe(c => AdaptionHints.Remove(AdaptionHints.FirstOrDefault(h => h.AdaptionHint == c.EventArgs.AdaptionHint)!))
.DisposeWith(d);
AdaptionHints.AddRange(Layer.Adapter.AdaptionHints.Select(CreateHintViewModel));
});
}
public Layer Layer { get; }
public ObservableCollection<AdaptionHintViewModelBase> AdaptionHints { get; }
public void Finish()
{
Close(true);
}
public void AutoDetermineHints()
{
Layer.Adapter.DetermineHints(_rgbService.EnabledDevices);
}
public void AddCategoryHint()
{
Layer.Adapter.Add(new CategoryAdaptionHint());
}
public void AddDeviceHint()
{
Layer.Adapter.Add(new DeviceAdaptionHint());
}
public void AddKeyboardSectionHint()
{
Layer.Adapter.Add(new KeyboardSectionAdaptionHint());
}
public void RemoveAdaptionHint(IAdaptionHint hint)
{
Layer.Adapter.Remove(hint);
}
private AdaptionHintViewModelBase CreateHintViewModel(IAdaptionHint hint)
{
return hint switch
{
CategoryAdaptionHint categoryAdaptionHint => _vmFactory.CategoryAdaptionHintViewModel(categoryAdaptionHint),
DeviceAdaptionHint deviceAdaptionHint => _vmFactory.DeviceAdaptionHintViewModel(deviceAdaptionHint),
KeyboardSectionAdaptionHint keyboardSectionAdaptionHint => _vmFactory.KeyboardSectionAdaptionHintViewModel(keyboardSectionAdaptionHint),
_ => throw new ArgumentOutOfRangeException(nameof(hint))
};
}
}

View File

@ -112,6 +112,11 @@
<avalonia:MaterialIcon Kind="LayersPlus" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Open adaption hints" Command="{CompiledBinding OpenAdaptionHints}">
<MenuItem.Icon>
<avalonia:MaterialIcon Kind="Magic" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="-" />
<MenuItem Header="Duplicate" Command="{CompiledBinding Duplicate}" InputGesture="Ctrl+D">
<MenuItem.Icon>

View File

@ -9,6 +9,7 @@ using System.Threading.Tasks;
using Artemis.Core;
using Artemis.UI.Extensions;
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.ProfileEditor;
@ -46,6 +47,7 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
AddLayer = ReactiveCommand.Create(ExecuteAddLayer);
AddFolder = ReactiveCommand.Create(ExecuteAddFolder);
OpenAdaptionHints = ReactiveCommand.CreateFromTask(ExecuteOpenAdaptionHints, this.WhenAnyValue(vm => vm.ProfileElement).Select(p => p is Layer));
Rename = ReactiveCommand.Create(ExecuteRename);
Delete = ReactiveCommand.Create(ExecuteDelete);
Duplicate = ReactiveCommand.CreateFromTask(ExecuteDuplicate);
@ -97,6 +99,7 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
public ReactiveCommand<Unit, Unit> AddLayer { get; }
public ReactiveCommand<Unit, Unit> AddFolder { get; }
public ReactiveCommand<Unit, Unit> OpenAdaptionHints { get; }
public ReactiveCommand<Unit, Unit> Rename { get; }
public ReactiveCommand<Unit, Unit> Duplicate { get; }
public ReactiveCommand<Unit, Unit> Copy { get; }
@ -248,6 +251,14 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
ProfileEditorService.CreateAndAddLayer(ProfileElement);
}
private async Task ExecuteOpenAdaptionHints()
{
if (ProfileElement is not Layer layer)
return;
await _windowService.ShowDialogAsync<LayerHintsDialogViewModel, bool>(("layer", layer));
}
private async void UpdateCanPaste(bool isFlyoutOpen)
{
if (Application.Current?.Clipboard == null)