mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Device properties - Implemented LED mappings tab
Device properties - Tweak design
This commit is contained in:
parent
78479c0fa2
commit
a06bc68046
10
src/.idea/.idea.Artemis/.idea/avalonia.xml
generated
10
src/.idea/.idea.Artemis/.idea/avalonia.xml
generated
@ -19,12 +19,21 @@
|
|||||||
<entry key="Artemis.UI/DefaultTypes/PropertyInput/ColorGradientPropertyInputView.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" />
|
||||||
<entry key="Artemis.UI/DefaultTypes/PropertyInput/SKSizePropertyInputView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/DefaultTypes/PropertyInput/SKSizePropertyInputView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<entry key="Artemis.UI/MainWindow.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/MainWindow.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
|
<entry key="Artemis.UI/Screens/Device/DevicePropertiesView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
|
<entry key="Artemis.UI/Screens/Device/DeviceSettingsView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
|
<entry key="Artemis.UI/Screens/Device/Tabs/DeviceInfoTabView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
|
<entry key="Artemis.UI/Screens/Device/Tabs/DevicePropertiesTabView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
|
<entry key="Artemis.UI/Screens/Device/Tabs/InputMappingsTabView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<entry key="Artemis.UI/Screens/Plugins/PluginFeatureView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<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/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/MenuBar/MenuBarView.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/ProfileTreeView.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/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" />
|
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/PropertiesView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
|
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/Keyframes/TimelineKeyframeView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
|
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/TimelineGroupView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
|
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Timeline/TimelinePropertyView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/ContentDialogs/LayerEffectRenameView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/ContentDialogs/LayerEffectRenameView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/ContentDialogs/SidebarCategoryEditView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/Screens/ProfileEditor/Panels/Properties/Tree/ContentDialogs/SidebarCategoryEditView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<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/TreeGroupView.axaml" value="Artemis.UI.Windows/Artemis.UI.Windows.csproj" />
|
||||||
@ -38,6 +47,7 @@
|
|||||||
<entry key="Artemis.UI/Screens/Sidebar/SidebarCategoryView.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/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" />
|
<entry key="Artemis.UI/Screens/Sidebar/SidebarView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
|
<entry key="Artemis.UI/Screens/SurfaceEditor/SurfaceEditorView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<entry key="Artemis.UI/Screens/VisualScripting/NodeView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Artemis.UI/Screens/VisualScripting/NodeView.axaml" value="Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<entry key="Avalonia/Artemis.UI/Screens/Debugger/Tabs/Render/RenderDebugView.axaml" value="Avalonia/Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Avalonia/Artemis.UI/Screens/Debugger/Tabs/Render/RenderDebugView.axaml" value="Avalonia/Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
<entry key="Avalonia/Artemis.UI/Styles/Artemis.axaml" value="Avalonia/Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
<entry key="Avalonia/Artemis.UI/Styles/Artemis.axaml" value="Avalonia/Artemis.UI.Linux/Artemis.UI.Linux.csproj" />
|
||||||
|
|||||||
@ -142,7 +142,10 @@ namespace Artemis.UI.Shared
|
|||||||
Point scaledPosition = new(x * Device.Rectangle.Width, y * Device.Rectangle.Height);
|
Point scaledPosition = new(x * Device.Rectangle.Width, y * Device.Rectangle.Height);
|
||||||
DeviceVisualizerLed? deviceVisualizerLed = _deviceVisualizerLeds.FirstOrDefault(l => l.HitTest(scaledPosition));
|
DeviceVisualizerLed? deviceVisualizerLed = _deviceVisualizerLeds.FirstOrDefault(l => l.HitTest(scaledPosition));
|
||||||
if (deviceVisualizerLed != null)
|
if (deviceVisualizerLed != null)
|
||||||
OnLedClicked(new LedClickedEventArgs(deviceVisualizerLed.Led.Device, deviceVisualizerLed.Led));
|
{
|
||||||
|
OnLedClicked(new LedClickedEventArgs(deviceVisualizerLed.Led.Device, deviceVisualizerLed.Led, e));
|
||||||
|
e.Handled = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DevicePropertyChanged(object? sender, PropertyChangedEventArgs e)
|
private void DevicePropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||||
|
|||||||
@ -1,27 +1,33 @@
|
|||||||
using System;
|
using System;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
|
using Avalonia.Input;
|
||||||
|
|
||||||
namespace Artemis.UI.Shared.Events
|
namespace Artemis.UI.Shared.Events;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Provides data on LED click events raised by the device visualizer
|
||||||
|
/// </summary>
|
||||||
|
public class LedClickedEventArgs : EventArgs
|
||||||
{
|
{
|
||||||
/// <summary>
|
internal LedClickedEventArgs(ArtemisDevice device, ArtemisLed led, PointerReleasedEventArgs pointerReleasedEventArgs)
|
||||||
/// Provides data on LED click events raised by the device visualizer
|
|
||||||
/// </summary>
|
|
||||||
public class LedClickedEventArgs : EventArgs
|
|
||||||
{
|
{
|
||||||
internal LedClickedEventArgs(ArtemisDevice device, ArtemisLed led)
|
Device = device;
|
||||||
{
|
Led = led;
|
||||||
Device = device;
|
PointerReleasedEventArgs = pointerReleasedEventArgs;
|
||||||
Led = led;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The device that was clicked
|
|
||||||
/// </summary>
|
|
||||||
public ArtemisDevice Device { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// The LED that was clicked
|
|
||||||
/// </summary>
|
|
||||||
public ArtemisLed Led { get; set; }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the device that was clicked.
|
||||||
|
/// </summary>
|
||||||
|
public ArtemisDevice Device { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the LED that was clicked.
|
||||||
|
/// </summary>
|
||||||
|
public ArtemisLed Led { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets the original pointer released event arguments.
|
||||||
|
/// </summary>
|
||||||
|
public PointerReleasedEventArgs PointerReleasedEventArgs { get; }
|
||||||
}
|
}
|
||||||
@ -1,16 +1,20 @@
|
|||||||
<controls1:CoreWindow xmlns="https://github.com/avaloniaui"
|
<controls1:CoreWindow xmlns="https://github.com/avaloniaui"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:controls1="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
xmlns:controls1="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||||
mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="800"
|
xmlns:device="clr-namespace:Artemis.UI.Screens.Device"
|
||||||
x:Class="Artemis.UI.Screens.Device.DevicePropertiesView"
|
mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="800"
|
||||||
Icon="/Assets/Images/Logo/application.ico"
|
x:Class="Artemis.UI.Screens.Device.DevicePropertiesView"
|
||||||
Title="Artemis | Device Properties"
|
x:DataType="device:DevicePropertiesViewModel"
|
||||||
Width="1250"
|
Icon="/Assets/Images/Logo/application.ico"
|
||||||
Height="900">
|
Title="Artemis | Device Properties"
|
||||||
|
Width="1250"
|
||||||
|
Height="900">
|
||||||
|
<controls1:CoreWindow.KeyBindings>
|
||||||
|
<KeyBinding Gesture="Escape" Command="{CompiledBinding ClearSelectedLeds}" />
|
||||||
|
</controls1:CoreWindow.KeyBindings>
|
||||||
<Grid ColumnDefinitions="*,0,1.5*">
|
<Grid ColumnDefinitions="*,0,1.5*">
|
||||||
<Grid.Background>
|
<Grid.Background>
|
||||||
<VisualBrush TileMode="Tile" Stretch="Uniform" DestinationRect="0,0,25,25">
|
<VisualBrush TileMode="Tile" Stretch="Uniform" DestinationRect="0,0,25,25">
|
||||||
@ -24,45 +28,46 @@
|
|||||||
</VisualBrush.Visual>
|
</VisualBrush.Visual>
|
||||||
</VisualBrush>
|
</VisualBrush>
|
||||||
</Grid.Background>
|
</Grid.Background>
|
||||||
<Grid Grid.Column="0" Name="DeviceDisplayGrid">
|
<Grid Grid.Column="0" Name="DeviceDisplayGrid" PointerReleased="DeviceDisplayGrid_OnPointerReleased">
|
||||||
<!-- No need to provide LEDs to highlight as LEDs are already physically highlighted -->
|
<!-- No need to provide LEDs to highlight as LEDs are already physically highlighted -->
|
||||||
<shared:DeviceVisualizer Device="{Binding Device}"
|
<shared:DeviceVisualizer Device="{CompiledBinding Device}"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
ShowColors="True"
|
ShowColors="True"
|
||||||
Margin="20" />
|
Margin="20"
|
||||||
|
LedClicked="DeviceVisualizer_OnLedClicked" />
|
||||||
|
|
||||||
<StackPanel Orientation="Horizontal"
|
<StackPanel Orientation="Horizontal"
|
||||||
VerticalAlignment="Bottom"
|
VerticalAlignment="Bottom"
|
||||||
HorizontalAlignment="Left"
|
HorizontalAlignment="Left"
|
||||||
Margin="15"
|
Margin="15"
|
||||||
IsVisible="{Binding Device.Layout.RgbLayout.Author, Converter={x:Static StringConverters.IsNotNullOrEmpty}}">
|
IsVisible="{CompiledBinding Device.Layout.RgbLayout.Author, Converter={x:Static StringConverters.IsNotNullOrEmpty}}">
|
||||||
<TextBlock Classes="h5" Text="Device layout by " />
|
<TextBlock Classes="h5" Text="Device layout by " />
|
||||||
<TextBlock Classes="h5" FontWeight="Bold" Text="{Binding Device.Layout.RgbLayout.Author}" />
|
<TextBlock Classes="h5" FontWeight="Bold" Text="{CompiledBinding Device.Layout.RgbLayout.Author}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
|
|
||||||
<GridSplitter Grid.Column="1" Width="15" Margin="-15 0 0 0" Background="Transparent" HorizontalAlignment="Stretch" />
|
<GridSplitter Grid.Column="1" Width="15" Margin="-15 0 0 0" Background="Transparent" HorizontalAlignment="Stretch" />
|
||||||
|
|
||||||
<Border Grid.Column="2" Classes="card" CornerRadius="10 0 0 0" Margin="0 10 0 0" Background="#ff323232">
|
<Border Grid.Column="2" Classes="card-condensed" CornerRadius="10 0 0 0" Margin="0 10 0 0" Background="#ff323232">
|
||||||
<TabControl Items="{Binding Tabs}">
|
<TabControl Items="{CompiledBinding Tabs}">
|
||||||
<TabControl.ItemTemplate>
|
<TabControl.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<TextBlock Text="{Binding DisplayName}" />
|
<TextBlock Text="{CompiledBinding DisplayName}" />
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</TabControl.ItemTemplate>
|
</TabControl.ItemTemplate>
|
||||||
<TabControl.ContentTemplate>
|
<TabControl.ContentTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
|
||||||
<ContentControl Content="{Binding}" Margin="0 10 0 0" />
|
<ContentControl Content="{Binding}" Margin="0 12" />
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</TabControl.ContentTemplate>
|
</TabControl.ContentTemplate>
|
||||||
</TabControl>
|
</TabControl>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<StackPanel Grid.Column="0" Grid.ColumnSpan="3" Classes="notification-container" Name="NotificationContainer" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
|
<StackPanel Grid.Column="0" Grid.ColumnSpan="3" Classes="notification-container" Name="NotificationContainer" VerticalAlignment="Bottom" HorizontalAlignment="Right" />
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
</controls1:CoreWindow>
|
</controls1:CoreWindow>
|
||||||
@ -1,22 +1,40 @@
|
|||||||
|
using System;
|
||||||
|
using Artemis.UI.Shared;
|
||||||
|
using Artemis.UI.Shared.Events;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
|
using Avalonia.Input;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
using Avalonia.ReactiveUI;
|
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Device
|
namespace Artemis.UI.Screens.Device;
|
||||||
|
|
||||||
|
public class DevicePropertiesView : ReactiveCoreWindow<DevicePropertiesViewModel>
|
||||||
{
|
{
|
||||||
public partial class DevicePropertiesView : ReactiveCoreWindow<DevicePropertiesViewModel>
|
public DevicePropertiesView()
|
||||||
{
|
{
|
||||||
public DevicePropertiesView()
|
InitializeComponent();
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
this.AttachDevTools();
|
this.AttachDevTools();
|
||||||
#endif
|
#endif
|
||||||
}
|
|
||||||
|
|
||||||
private void InitializeComponent()
|
|
||||||
{
|
|
||||||
AvaloniaXamlLoader.Load(this);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
private void InitializeComponent()
|
||||||
|
{
|
||||||
|
AvaloniaXamlLoader.Load(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeviceVisualizer_OnLedClicked(object? sender, LedClickedEventArgs e)
|
||||||
|
{
|
||||||
|
if (ViewModel == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!e.PointerReleasedEventArgs.KeyModifiers.HasFlag(KeyModifiers.Shift))
|
||||||
|
ViewModel.SelectedLeds.Clear();
|
||||||
|
ViewModel.SelectedLeds.Add(e.Led);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void DeviceDisplayGrid_OnPointerReleased(object? sender, PointerReleasedEventArgs e)
|
||||||
|
{
|
||||||
|
if (!e.KeyModifiers.HasFlag(KeyModifiers.Shift))
|
||||||
|
ViewModel?.ClearSelectedLeds.Execute().Subscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,15 +1,22 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System;
|
||||||
|
using System.Collections.ObjectModel;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Reactive;
|
||||||
|
using System.Reactive.Disposables;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Services;
|
||||||
using Artemis.UI.Ninject.Factories;
|
using Artemis.UI.Ninject.Factories;
|
||||||
using Artemis.UI.Shared;
|
using Artemis.UI.Shared;
|
||||||
|
using ReactiveUI;
|
||||||
using RGB.NET.Core;
|
using RGB.NET.Core;
|
||||||
|
using SkiaSharp;
|
||||||
using ArtemisLed = Artemis.Core.ArtemisLed;
|
using ArtemisLed = Artemis.Core.ArtemisLed;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Device
|
namespace Artemis.UI.Screens.Device
|
||||||
{
|
{
|
||||||
public class DevicePropertiesViewModel : DialogViewModelBase<object>
|
public class DevicePropertiesViewModel : DialogViewModelBase<object>
|
||||||
{
|
{
|
||||||
public DevicePropertiesViewModel(ArtemisDevice device, IDeviceVmFactory deviceVmFactory)
|
public DevicePropertiesViewModel(ArtemisDevice device, ICoreService coreService, IDeviceVmFactory deviceVmFactory)
|
||||||
{
|
{
|
||||||
Device = device;
|
Device = device;
|
||||||
SelectedLeds = new ObservableCollection<ArtemisLed>();
|
SelectedLeds = new ObservableCollection<ArtemisLed>();
|
||||||
@ -17,13 +24,39 @@ namespace Artemis.UI.Screens.Device
|
|||||||
|
|
||||||
Tabs.Add(deviceVmFactory.DevicePropertiesTabViewModel(device));
|
Tabs.Add(deviceVmFactory.DevicePropertiesTabViewModel(device));
|
||||||
Tabs.Add(deviceVmFactory.DeviceInfoTabViewModel(device));
|
Tabs.Add(deviceVmFactory.DeviceInfoTabViewModel(device));
|
||||||
if (Device .DeviceType == RGBDeviceType.Keyboard)
|
if (Device.DeviceType == RGBDeviceType.Keyboard)
|
||||||
Tabs.Add(deviceVmFactory.InputMappingsTabViewModel(device, SelectedLeds));
|
Tabs.Add(deviceVmFactory.InputMappingsTabViewModel(device, SelectedLeds));
|
||||||
Tabs.Add(deviceVmFactory.DeviceLedsTabViewModel(device, SelectedLeds));
|
Tabs.Add(deviceVmFactory.DeviceLedsTabViewModel(device, SelectedLeds));
|
||||||
|
|
||||||
|
this.WhenActivated(d =>
|
||||||
|
{
|
||||||
|
coreService.FrameRendering += CoreServiceOnFrameRendering;
|
||||||
|
Disposable.Create(() => coreService.FrameRendering -= CoreServiceOnFrameRendering).DisposeWith(d);
|
||||||
|
});
|
||||||
|
|
||||||
|
ClearSelectedLeds = ReactiveCommand.Create(ExecuteClearSelectedLeds);
|
||||||
}
|
}
|
||||||
|
|
||||||
public ArtemisDevice Device { get; }
|
public ArtemisDevice Device { get; }
|
||||||
public ObservableCollection<ArtemisLed> SelectedLeds { get; }
|
public ObservableCollection<ArtemisLed> SelectedLeds { get; }
|
||||||
public ObservableCollection<ActivatableViewModelBase> Tabs { get; }
|
public ObservableCollection<ActivatableViewModelBase> Tabs { get; }
|
||||||
|
|
||||||
|
public ReactiveCommand<Unit, Unit> ClearSelectedLeds { get; }
|
||||||
|
|
||||||
|
private void ExecuteClearSelectedLeds()
|
||||||
|
{
|
||||||
|
SelectedLeds.Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CoreServiceOnFrameRendering(object? sender, FrameRenderingEventArgs e)
|
||||||
|
{
|
||||||
|
if (!SelectedLeds.Any())
|
||||||
|
return;
|
||||||
|
|
||||||
|
using SKPaint highlightPaint = new() {Color = SKColors.White};
|
||||||
|
using SKPaint dimPaint = new() {Color = new SKColor(0, 0, 0, 192)};
|
||||||
|
foreach (ArtemisLed artemisLed in Device.Leds)
|
||||||
|
e.Canvas.DrawRect(artemisLed.AbsoluteRectangle, SelectedLeds.Contains(artemisLed) ? highlightPaint : dimPaint);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,9 +1,10 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Device
|
namespace Artemis.UI.Screens.Device
|
||||||
{
|
{
|
||||||
public partial class DeviceInfoTabView : UserControl
|
public partial class DeviceInfoTabView : ReactiveUserControl<DeviceInfoTabViewModel>
|
||||||
{
|
{
|
||||||
public DeviceInfoTabView()
|
public DeviceInfoTabView()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -1,9 +1,10 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Device
|
namespace Artemis.UI.Screens.Device
|
||||||
{
|
{
|
||||||
public partial class DeviceLedsTabView : UserControl
|
public partial class DeviceLedsTabView : ReactiveUserControl<DeviceLedsTabViewModel>
|
||||||
{
|
{
|
||||||
public DeviceLedsTabView()
|
public DeviceLedsTabView()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -138,7 +138,12 @@
|
|||||||
ClipValueToMinMax="True" />
|
ClipValueToMinMax="True" />
|
||||||
|
|
||||||
<CheckBox Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" IsChecked="{Binding DisplayOnDevices}" Content="Show preview" VerticalAlignment="Center" />
|
<CheckBox Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" IsChecked="{Binding DisplayOnDevices}" Content="Show preview" VerticalAlignment="Center" />
|
||||||
<controls:ColorPickerButton Grid.Row="3" Grid.Column="2" VerticalAlignment="Center" HorizontalAlignment="Right" Color="{Binding CurrentColor, Converter={StaticResource SKColorToColorConverter}}" />
|
<controls:ColorPickerButton Grid.Row="3"
|
||||||
|
Grid.Column="2"
|
||||||
|
VerticalAlignment="Center"
|
||||||
|
HorizontalAlignment="Right"
|
||||||
|
Color="{Binding CurrentColor, Converter={StaticResource SKColorToColorConverter}}"
|
||||||
|
ShowAcceptDismissButtons="False" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -168,7 +173,7 @@
|
|||||||
UseFloatingWatermark="True"
|
UseFloatingWatermark="True"
|
||||||
IsReadOnly="True"
|
IsReadOnly="True"
|
||||||
PointerReleased="InputElement_OnPointerReleased"
|
PointerReleased="InputElement_OnPointerReleased"
|
||||||
Padding="10 5 36 6"/>
|
Padding="10 5 36 6" />
|
||||||
<Button Classes="AppBarButton" HorizontalAlignment="Right" Command="{Binding ClearCustomLayout}" Padding="6" Margin="5 0">
|
<Button Classes="AppBarButton" HorizontalAlignment="Right" Command="{Binding ClearCustomLayout}" Padding="6" Margin="5 0">
|
||||||
<avalonia:MaterialIcon Kind="CloseCircle" />
|
<avalonia:MaterialIcon Kind="CloseCircle" />
|
||||||
</Button>
|
</Button>
|
||||||
@ -181,16 +186,13 @@
|
|||||||
|
|
||||||
<!-- Buttons -->
|
<!-- Buttons -->
|
||||||
<Grid Grid.Row="1" ColumnDefinitions="Auto,*">
|
<Grid Grid.Row="1" ColumnDefinitions="Auto,*">
|
||||||
<Button Grid.Column="0"
|
<Button Grid.Column="0" Command="{Binding SelectPhysicalLayout}" ToolTip.Tip="Restart device setup, allowing you to select a new physical and logical layout">
|
||||||
Classes="AppBarButton"
|
|
||||||
Command="{Binding SelectPhysicalLayout}"
|
|
||||||
ToolTip.Tip="Restart device setup, allowing you to select a new physical and logical layout">
|
|
||||||
Restart setup
|
Restart setup
|
||||||
</Button>
|
</Button>
|
||||||
|
|
||||||
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right">
|
<StackPanel Grid.Column="1" Orientation="Horizontal" HorizontalAlignment="Right">
|
||||||
<Button Classes="AppBarButton" IsCancel="True" Command="{Binding Reset}" Margin="0 0 5 0">Reset</Button>
|
<Button IsCancel="True" Command="{Binding Reset}" Margin="0 0 5 0">Reset</Button>
|
||||||
<Button IsDefault="True" Command="{Binding Apply}">Apply</Button>
|
<Button Classes="accent" IsDefault="True" Command="{Binding Apply}">Apply</Button>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|||||||
@ -240,9 +240,9 @@ namespace Artemis.UI.Screens.Device
|
|||||||
HasRoomCategory = Device.Categories.Contains(DeviceCategory.Room);
|
HasRoomCategory = Device.Categories.Contains(DeviceCategory.Room);
|
||||||
HasPeripheralsCategory = Device.Categories.Contains(DeviceCategory.Peripherals);
|
HasPeripheralsCategory = Device.Categories.Contains(DeviceCategory.Peripherals);
|
||||||
|
|
||||||
Device.RedScale = _initialRedScale;
|
RedScale = _initialRedScale * 100;
|
||||||
Device.GreenScale = _initialGreenScale;
|
GreenScale = _initialGreenScale * 100;
|
||||||
Device.BlueScale = _initialBlueScale;
|
BlueScale = _initialBlueScale * 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool GetCategory(DeviceCategory category)
|
private bool GetCategory(DeviceCategory category)
|
||||||
@ -254,7 +254,7 @@ namespace Artemis.UI.Screens.Device
|
|||||||
{
|
{
|
||||||
if (value && !_categories.Contains(category))
|
if (value && !_categories.Contains(category))
|
||||||
_categories.Add(category);
|
_categories.Add(category);
|
||||||
else
|
else if (!value)
|
||||||
_categories.Remove(category);
|
_categories.Remove(category);
|
||||||
|
|
||||||
this.RaisePropertyChanged($"Has{category}Category");
|
this.RaisePropertyChanged($"Has{category}Category");
|
||||||
|
|||||||
@ -2,7 +2,73 @@
|
|||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:device="clr-namespace:Artemis.UI.Screens.Device"
|
||||||
|
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.Device.InputMappingsTabView">
|
x:Class="Artemis.UI.Screens.Device.InputMappingsTabView"
|
||||||
Welcome to Avalonia!
|
x:DataType="device:InputMappingsTabViewModel">
|
||||||
</UserControl>
|
<Grid>
|
||||||
|
<Grid.RowDefinitions>
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="Auto" />
|
||||||
|
<RowDefinition Height="*" />
|
||||||
|
</Grid.RowDefinitions>
|
||||||
|
<StackPanel Grid.Row="0">
|
||||||
|
<TextBlock Classes="h4">
|
||||||
|
Introduction
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock TextWrapping="Wrap">
|
||||||
|
In some cases you may want Artemis to map key presses to different LEDs.
|
||||||
|
</TextBlock>
|
||||||
|
<TextBlock TextWrapping="Wrap" Margin="0 13 0 0">
|
||||||
|
This is useful when your logical layout swaps keys around (like Hungarian layouts where the Z and Y keys are swapped). In this tab you can set up these custom input mappings, simply click on a LED and press a key, Artemis will from then on consider that LED pressed whenever you press the same key again.
|
||||||
|
</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<TextBlock Grid.Row="1"
|
||||||
|
Margin="0 20"
|
||||||
|
Classes="h4"
|
||||||
|
TextAlignment="Center"
|
||||||
|
IsVisible="{CompiledBinding SelectedLed, Converter={x:Static ObjectConverters.IsNull}}">
|
||||||
|
Select a LED in the preview on the left side to get started...
|
||||||
|
</TextBlock>
|
||||||
|
|
||||||
|
<StackPanel Grid.Row="1" Margin="0 20" IsVisible="{CompiledBinding SelectedLed, Converter={x:Static ObjectConverters.IsNotNull}}">
|
||||||
|
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Spacing="6">
|
||||||
|
<TextBlock Classes="h4" TextAlignment="Center">Current target LED: </TextBlock>
|
||||||
|
<TextBlock Classes="h4" TextAlignment="Center" Text="{CompiledBinding SelectedLed.RgbLed.Id, Mode=OneWay, FallbackValue='none'}"/>
|
||||||
|
</StackPanel>
|
||||||
|
<StackPanel HorizontalAlignment="Center" Orientation="Horizontal" Spacing="5">
|
||||||
|
<TextBlock TextAlignment="Center">Press the key you want to remap</TextBlock>
|
||||||
|
<TextBlock TextAlignment="Center" FontWeight="Bold" Text="{CompiledBinding SelectedLed.RgbLed.Id, Mode=OneWay, FallbackValue='none'}"/>
|
||||||
|
<TextBlock TextAlignment="Center">to ...</TextBlock>
|
||||||
|
</StackPanel>
|
||||||
|
</StackPanel>
|
||||||
|
|
||||||
|
<DataGrid Grid.Row="2"
|
||||||
|
Items="{CompiledBinding InputMappings}"
|
||||||
|
CanUserSortColumns="True"
|
||||||
|
IsReadOnly="True"
|
||||||
|
AutoGenerateColumns="False"
|
||||||
|
Margin="10">
|
||||||
|
<DataGrid.Columns>
|
||||||
|
<DataGridTextColumn Binding="{Binding [0].RgbLed.Id}" Header="Original LED ID" Width="*" />
|
||||||
|
<DataGridTextColumn Binding="{Binding [1].RgbLed.Id}" Header="Remapped LED ID" Width="*" />
|
||||||
|
|
||||||
|
<DataGridTemplateColumn Width="Auto" IsReadOnly="True">
|
||||||
|
<DataGridTemplateColumn.CellTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<Button Command="{Binding $parent[UserControl].DataContext.DeleteMapping}"
|
||||||
|
CommandParameter="{Binding}"
|
||||||
|
Classes="icon-button"
|
||||||
|
ToolTip.Tip="Delete mapping"
|
||||||
|
HorizontalAlignment="Center">
|
||||||
|
<avalonia:MaterialIcon Kind="Delete" />
|
||||||
|
</Button>
|
||||||
|
</DataTemplate>
|
||||||
|
</DataGridTemplateColumn.CellTemplate>
|
||||||
|
</DataGridTemplateColumn>
|
||||||
|
</DataGrid.Columns>
|
||||||
|
</DataGrid>
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
||||||
@ -1,9 +1,10 @@
|
|||||||
using Avalonia.Controls;
|
using Avalonia.Controls;
|
||||||
using Avalonia.Markup.Xaml;
|
using Avalonia.Markup.Xaml;
|
||||||
|
using Avalonia.ReactiveUI;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Device
|
namespace Artemis.UI.Screens.Device
|
||||||
{
|
{
|
||||||
public partial class InputMappingsTabView : UserControl
|
public partial class InputMappingsTabView : ReactiveUserControl<InputMappingsTabViewModel>
|
||||||
{
|
{
|
||||||
public InputMappingsTabView()
|
public InputMappingsTabView()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -2,6 +2,7 @@
|
|||||||
using System.Collections.ObjectModel;
|
using System.Collections.ObjectModel;
|
||||||
using System.Collections.Specialized;
|
using System.Collections.Specialized;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
using System.Reactive.Disposables;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
using Artemis.UI.Exceptions;
|
using Artemis.UI.Exceptions;
|
||||||
@ -30,8 +31,23 @@ namespace Artemis.UI.Screens.Device
|
|||||||
Device = device;
|
Device = device;
|
||||||
DisplayName = "Input Mappings";
|
DisplayName = "Input Mappings";
|
||||||
InputMappings = new ObservableCollection<(ArtemisLed, ArtemisLed)>();
|
InputMappings = new ObservableCollection<(ArtemisLed, ArtemisLed)>();
|
||||||
|
|
||||||
|
this.WhenActivated(d =>
|
||||||
|
{
|
||||||
|
_selectedLeds.CollectionChanged += SelectedLedsOnCollectionChanged;
|
||||||
|
_inputService.KeyboardKeyUp += InputServiceOnKeyboardKeyUp;
|
||||||
|
UpdateInputMappings();
|
||||||
|
|
||||||
|
Disposable.Create(() =>
|
||||||
|
{
|
||||||
|
_selectedLeds.CollectionChanged -= SelectedLedsOnCollectionChanged;
|
||||||
|
_inputService.KeyboardKeyUp -= InputServiceOnKeyboardKeyUp;
|
||||||
|
InputMappings.Clear();
|
||||||
|
}).DisposeWith(d);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public ArtemisDevice Device { get; }
|
public ArtemisDevice Device { get; }
|
||||||
|
|
||||||
public ArtemisLed? SelectedLed
|
public ArtemisLed? SelectedLed
|
||||||
@ -42,13 +58,13 @@ namespace Artemis.UI.Screens.Device
|
|||||||
|
|
||||||
public ObservableCollection<(ArtemisLed, ArtemisLed)> InputMappings { get; }
|
public ObservableCollection<(ArtemisLed, ArtemisLed)> InputMappings { get; }
|
||||||
|
|
||||||
public void DeleteMapping(Tuple<ArtemisLed, ArtemisLed> inputMapping)
|
public void DeleteMapping((ArtemisLed, ArtemisLed) inputMapping)
|
||||||
{
|
{
|
||||||
Device.InputMappings.Remove(inputMapping.Item1);
|
Device.InputMappings.Remove(inputMapping.Item1);
|
||||||
UpdateInputMappings();
|
UpdateInputMappings();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InputServiceOnKeyboardKeyUp(object sender, ArtemisKeyboardKeyEventArgs e)
|
private void InputServiceOnKeyboardKeyUp(object? sender, ArtemisKeyboardKeyEventArgs e)
|
||||||
{
|
{
|
||||||
if (SelectedLed == null || e.Led == null)
|
if (SelectedLed == null || e.Led == null)
|
||||||
return;
|
return;
|
||||||
@ -64,7 +80,7 @@ namespace Artemis.UI.Screens.Device
|
|||||||
// Apply the new LED mapping
|
// Apply the new LED mapping
|
||||||
Device.InputMappings[SelectedLed] = artemisLed;
|
Device.InputMappings[SelectedLed] = artemisLed;
|
||||||
_rgbService.SaveDevice(Device);
|
_rgbService.SaveDevice(Device);
|
||||||
// ((DeviceDialogViewModel) Parent).SelectedLeds.Clear();
|
_selectedLeds.Clear();
|
||||||
|
|
||||||
UpdateInputMappings();
|
UpdateInputMappings();
|
||||||
}
|
}
|
||||||
@ -74,35 +90,13 @@ namespace Artemis.UI.Screens.Device
|
|||||||
if (InputMappings.Any())
|
if (InputMappings.Any())
|
||||||
InputMappings.Clear();
|
InputMappings.Clear();
|
||||||
|
|
||||||
// InputMappings.AddRange(Device.InputMappings.Select(m => new Tuple<ArtemisLed, ArtemisLed>(m.Key, m.Value)));
|
foreach ((ArtemisLed, ArtemisLed) tuple in Device.InputMappings.Select(m => (m.Key, m.Value)))
|
||||||
|
InputMappings.Add(tuple);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void SelectedLedsOnCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
|
private void SelectedLedsOnCollectionChanged(object? sender, NotifyCollectionChangedEventArgs e)
|
||||||
{
|
{
|
||||||
// SelectedLed = ((DeviceDialogViewModel) Parent).SelectedLeds.FirstOrDefault();
|
SelectedLed = _selectedLeds.FirstOrDefault();
|
||||||
}
|
}
|
||||||
//
|
|
||||||
// #region Overrides of Screen
|
|
||||||
//
|
|
||||||
// /// <inheritdoc />
|
|
||||||
// protected override void OnActivate()
|
|
||||||
// {
|
|
||||||
// UpdateInputMappings();
|
|
||||||
// _inputService.KeyboardKeyUp += InputServiceOnKeyboardKeyUp;
|
|
||||||
// ((DeviceDialogViewModel) Parent).SelectedLeds.CollectionChanged += SelectedLedsOnCollectionChanged;
|
|
||||||
//
|
|
||||||
// base.OnActivate();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /// <inheritdoc />
|
|
||||||
// protected override void OnDeactivate()
|
|
||||||
// {
|
|
||||||
// InputMappings.Clear();
|
|
||||||
// _inputService.KeyboardKeyUp -= InputServiceOnKeyboardKeyUp;
|
|
||||||
// ((DeviceDialogViewModel) Parent).SelectedLeds.CollectionChanged -= SelectedLedsOnCollectionChanged;
|
|
||||||
// base.OnDeactivate();
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// #endregion
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -35,7 +35,7 @@
|
|||||||
<avalonia:MaterialIcon Kind="BookEdit" />
|
<avalonia:MaterialIcon Kind="BookEdit" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<MenuItem Header="Adapt Profile" Command="{Binding AdaptProfile}">
|
<MenuItem Header="Adapt Profile" Command="{CompiledBinding AdaptProfile}">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="Magic" />
|
<avalonia:MaterialIcon Kind="Magic" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
|
|||||||
@ -55,6 +55,7 @@ public class MenuBarViewModel : ActivatableViewModelBase
|
|||||||
AddFolder = ReactiveCommand.Create(ExecuteAddFolder);
|
AddFolder = ReactiveCommand.Create(ExecuteAddFolder);
|
||||||
AddLayer = ReactiveCommand.Create(ExecuteAddLayer);
|
AddLayer = ReactiveCommand.Create(ExecuteAddLayer);
|
||||||
ViewProperties = ReactiveCommand.CreateFromTask(ExecuteViewProperties, this.WhenAnyValue(vm => vm.ProfileConfiguration).Select(c => c != null));
|
ViewProperties = ReactiveCommand.CreateFromTask(ExecuteViewProperties, this.WhenAnyValue(vm => vm.ProfileConfiguration).Select(c => c != null));
|
||||||
|
AdaptProfile = ReactiveCommand.CreateFromTask(ExecuteAdaptProfile, this.WhenAnyValue(vm => vm.ProfileConfiguration).Select(c => c != null));
|
||||||
ToggleSuspended = ReactiveCommand.Create(ExecuteToggleSuspended, this.WhenAnyValue(vm => vm.ProfileConfiguration).Select(c => c != null));
|
ToggleSuspended = ReactiveCommand.Create(ExecuteToggleSuspended, this.WhenAnyValue(vm => vm.ProfileConfiguration).Select(c => c != null));
|
||||||
DeleteProfile = ReactiveCommand.CreateFromTask(ExecuteDeleteProfile, this.WhenAnyValue(vm => vm.ProfileConfiguration).Select(c => c != null));
|
DeleteProfile = ReactiveCommand.CreateFromTask(ExecuteDeleteProfile, this.WhenAnyValue(vm => vm.ProfileConfiguration).Select(c => c != null));
|
||||||
ExportProfile = ReactiveCommand.CreateFromTask(ExecuteExportProfile, this.WhenAnyValue(vm => vm.ProfileConfiguration).Select(c => c != null));
|
ExportProfile = ReactiveCommand.CreateFromTask(ExecuteExportProfile, this.WhenAnyValue(vm => vm.ProfileConfiguration).Select(c => c != null));
|
||||||
@ -68,6 +69,7 @@ public class MenuBarViewModel : ActivatableViewModelBase
|
|||||||
public ReactiveCommand<Unit, Unit> AddLayer { get; }
|
public ReactiveCommand<Unit, Unit> AddLayer { get; }
|
||||||
public ReactiveCommand<Unit, Unit> ToggleSuspended { get; }
|
public ReactiveCommand<Unit, Unit> ToggleSuspended { get; }
|
||||||
public ReactiveCommand<Unit, Unit> ViewProperties { get; }
|
public ReactiveCommand<Unit, Unit> ViewProperties { get; }
|
||||||
|
public ReactiveCommand<Unit,Unit> AdaptProfile { get; }
|
||||||
public ReactiveCommand<Unit, Unit> DeleteProfile { get; }
|
public ReactiveCommand<Unit, Unit> DeleteProfile { get; }
|
||||||
public ReactiveCommand<Unit, Unit> ExportProfile { get; }
|
public ReactiveCommand<Unit, Unit> ExportProfile { get; }
|
||||||
public ReactiveCommand<Unit, Unit> DuplicateProfile { get; }
|
public ReactiveCommand<Unit, Unit> DuplicateProfile { get; }
|
||||||
@ -121,6 +123,16 @@ public class MenuBarViewModel : ActivatableViewModelBase
|
|||||||
("profileConfiguration", ProfileConfiguration)
|
("profileConfiguration", ProfileConfiguration)
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
private async Task ExecuteAdaptProfile()
|
||||||
|
{
|
||||||
|
if (ProfileConfiguration?.Profile == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (!await _windowService.ShowConfirmContentDialog("Adapt profile", "Are you sure you want to adapt the profile to your current surface? Layer assignments may change."))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_profileService.AdaptProfile(ProfileConfiguration.Profile);
|
||||||
|
}
|
||||||
|
|
||||||
private void ExecuteToggleSuspended()
|
private void ExecuteToggleSuspended()
|
||||||
{
|
{
|
||||||
|
|||||||
@ -56,6 +56,19 @@ public class FolderTreeItemViewModel : TreeItemViewModel
|
|||||||
ProfileEditorService.ExecuteCommand(new AddProfileElement(pasted, parent, Folder.Order - 1));
|
ProfileEditorService.ExecuteCommand(new AddProfileElement(pasted, parent, Folder.Order - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async Task ExecutePasteInto()
|
||||||
|
{
|
||||||
|
RenderProfileElement? pasted = await Folder.PasteChildFromClipboard();
|
||||||
|
if (pasted == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// If the target contains an element with the same name, affix with " - copy"
|
||||||
|
if (Folder.Children.Any(c => c.Name == pasted.Name))
|
||||||
|
pasted.Name = Folder.GetNewFolderName(pasted.Name + " - copy");
|
||||||
|
|
||||||
|
ProfileEditorService.ExecuteCommand(new AddProfileElement(pasted, Folder, 0));
|
||||||
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override bool SupportsChildren => true;
|
public override bool SupportsChildren => true;
|
||||||
|
|
||||||
|
|||||||
@ -112,7 +112,7 @@
|
|||||||
<avalonia:MaterialIcon Kind="LayersPlus" />
|
<avalonia:MaterialIcon Kind="LayersPlus" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<Separator />
|
<MenuItem Header="-" />
|
||||||
<MenuItem Header="Duplicate" Command="{CompiledBinding Duplicate}" InputGesture="Ctrl+D">
|
<MenuItem Header="Duplicate" Command="{CompiledBinding Duplicate}" InputGesture="Ctrl+D">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="ContentDuplicate" />
|
<avalonia:MaterialIcon Kind="ContentDuplicate" />
|
||||||
@ -128,7 +128,7 @@
|
|||||||
<avalonia:MaterialIcon Kind="ContentPaste" />
|
<avalonia:MaterialIcon Kind="ContentPaste" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<Separator />
|
<MenuItem Header="-" />
|
||||||
<MenuItem Header="Rename" Command="{CompiledBinding Rename}" InputGesture="F2">
|
<MenuItem Header="Rename" Command="{CompiledBinding Rename}" InputGesture="F2">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="RenameBox" />
|
<avalonia:MaterialIcon Kind="RenameBox" />
|
||||||
|
|||||||
@ -6,8 +6,7 @@
|
|||||||
xmlns:timeline="clr-namespace:Artemis.UI.Screens.ProfileEditor.Properties.Timeline"
|
xmlns:timeline="clr-namespace:Artemis.UI.Screens.ProfileEditor.Properties.Timeline"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Keyframes.TimelineKeyframeView"
|
x:Class="Artemis.UI.Screens.ProfileEditor.Properties.Timeline.Keyframes.TimelineKeyframeView"
|
||||||
ClipToBounds="False"
|
ClipToBounds="False">
|
||||||
Height="{DynamicResource RailsHeight}">
|
|
||||||
<Ellipse Fill="{DynamicResource SystemAccentColorLight2}"
|
<Ellipse Fill="{DynamicResource SystemAccentColorLight2}"
|
||||||
Stroke="White"
|
Stroke="White"
|
||||||
Width="10"
|
Width="10"
|
||||||
@ -52,7 +51,7 @@
|
|||||||
<avalonia:MaterialIcon Kind="Creation" />
|
<avalonia:MaterialIcon Kind="Creation" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<Separator />
|
<MenuItem Header="-" />
|
||||||
<MenuItem Header="Duplicate" Command="{Binding $parent[timeline:TimelineView].DataContext.DuplicateKeyframes}" CommandParameter="{Binding}" InputGesture="Ctrl+D">
|
<MenuItem Header="Duplicate" Command="{Binding $parent[timeline:TimelineView].DataContext.DuplicateKeyframes}" CommandParameter="{Binding}" InputGesture="Ctrl+D">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="ContentDuplicate" />
|
<avalonia:MaterialIcon Kind="ContentDuplicate" />
|
||||||
@ -68,7 +67,7 @@
|
|||||||
<avalonia:MaterialIcon Kind="ContentPaste" />
|
<avalonia:MaterialIcon Kind="ContentPaste" />
|
||||||
</MenuItem.Icon>
|
</MenuItem.Icon>
|
||||||
</MenuItem>
|
</MenuItem>
|
||||||
<Separator />
|
<MenuItem Header="-" />
|
||||||
<MenuItem Header="Delete" Command="{Binding $parent[timeline:TimelineView].DataContext.DeleteKeyframes}" CommandParameter="{Binding}" InputGesture="Delete">
|
<MenuItem Header="Delete" Command="{Binding $parent[timeline:TimelineView].DataContext.DeleteKeyframes}" CommandParameter="{Binding}" InputGesture="Delete">
|
||||||
<MenuItem.Icon>
|
<MenuItem.Icon>
|
||||||
<avalonia:MaterialIcon Kind="Delete" />
|
<avalonia:MaterialIcon Kind="Delete" />
|
||||||
|
|||||||
@ -9,7 +9,7 @@
|
|||||||
x:DataType="timeline:TimelineGroupViewModel">
|
x:DataType="timeline:TimelineGroupViewModel">
|
||||||
<Grid RowDefinitions="28,1,Auto">
|
<Grid RowDefinitions="28,1,Auto">
|
||||||
<ItemsControl Grid.Row="0"
|
<ItemsControl Grid.Row="0"
|
||||||
Height="{DynamicResource RailsHeight}"
|
Height="28"
|
||||||
IsVisible="{CompiledBinding !PropertyGroupViewModel.IsExpanded}"
|
IsVisible="{CompiledBinding !PropertyGroupViewModel.IsExpanded}"
|
||||||
Items="{CompiledBinding KeyframePositions}"
|
Items="{CompiledBinding KeyframePositions}"
|
||||||
HorizontalAlignment="Stretch">
|
HorizontalAlignment="Stretch">
|
||||||
@ -21,16 +21,17 @@
|
|||||||
<ItemsControl.Styles>
|
<ItemsControl.Styles>
|
||||||
<Style Selector="ContentPresenter">
|
<Style Selector="ContentPresenter">
|
||||||
<Setter Property="Canvas.Left" Value="{Binding}" />
|
<Setter Property="Canvas.Left" Value="{Binding}" />
|
||||||
|
<Setter Property="Canvas.Top" Value="9" />
|
||||||
</Style>
|
</Style>
|
||||||
</ItemsControl.Styles>
|
</ItemsControl.Styles>
|
||||||
<ItemsControl.ItemTemplate>
|
<ItemsControl.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<Ellipse Fill="{DynamicResource ControlFillColorDisabledBrush}"
|
<Ellipse Fill="{DynamicResource ControlSolidFillColorDefaultBrush}"
|
||||||
Stroke="White"
|
Stroke="White"
|
||||||
StrokeThickness="0"
|
StrokeThickness="0"
|
||||||
Width="10"
|
Width="10"
|
||||||
Height="10"
|
Height="10"
|
||||||
Margin="-5,6,0,0" />
|
Margin="-5 0 0 0" />
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ItemsControl.ItemTemplate>
|
</ItemsControl.ItemTemplate>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
|||||||
@ -11,7 +11,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Properties.Timeline;
|
|||||||
public class TimelineGroupViewModel : ActivatableViewModelBase
|
public class TimelineGroupViewModel : ActivatableViewModelBase
|
||||||
{
|
{
|
||||||
private ObservableCollection<double>? _keyframePositions;
|
private ObservableCollection<double>? _keyframePositions;
|
||||||
private int _pixelsPerSecond;
|
private ObservableAsPropertyHelper<int>? _pixelsPerSecond;
|
||||||
|
|
||||||
public TimelineGroupViewModel(PropertyGroupViewModel propertyGroupViewModel, IProfileEditorService profileEditorService)
|
public TimelineGroupViewModel(PropertyGroupViewModel propertyGroupViewModel, IProfileEditorService profileEditorService)
|
||||||
{
|
{
|
||||||
@ -19,16 +19,16 @@ public class TimelineGroupViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
this.WhenActivated(d =>
|
this.WhenActivated(d =>
|
||||||
{
|
{
|
||||||
profileEditorService.PixelsPerSecond.Subscribe(p =>
|
_pixelsPerSecond = profileEditorService.PixelsPerSecond.ToProperty(this, vm => vm.PixelsPerSecond).DisposeWith(d);
|
||||||
{
|
profileEditorService.PixelsPerSecond.Subscribe(p => UpdateKeyframePositions()).DisposeWith(d);
|
||||||
_pixelsPerSecond = p;
|
|
||||||
UpdateKeyframePositions();
|
|
||||||
}).DisposeWith(d);
|
|
||||||
this.WhenAnyValue(vm => vm.PropertyGroupViewModel.IsExpanded).Subscribe(_ => UpdateKeyframePositions()).DisposeWith(d);
|
|
||||||
PropertyGroupViewModel.WhenAnyValue(vm => vm.IsExpanded).Subscribe(_ => this.RaisePropertyChanged(nameof(Children))).DisposeWith(d);
|
PropertyGroupViewModel.WhenAnyValue(vm => vm.IsExpanded).Subscribe(_ => this.RaisePropertyChanged(nameof(Children))).DisposeWith(d);
|
||||||
|
PropertyGroupViewModel.WhenAnyValue(vm => vm.IsExpanded).Subscribe(_ => UpdateKeyframePositions()).DisposeWith(d);
|
||||||
|
this.WhenAnyValue(vm => vm.PixelsPerSecond).Subscribe(_ => UpdateKeyframePositions()).DisposeWith(d);
|
||||||
|
UpdateKeyframePositions();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int PixelsPerSecond => _pixelsPerSecond?.Value ?? 0;
|
||||||
public PropertyGroupViewModel PropertyGroupViewModel { get; }
|
public PropertyGroupViewModel PropertyGroupViewModel { get; }
|
||||||
|
|
||||||
public ObservableCollection<ViewModelBase>? Children => PropertyGroupViewModel.IsExpanded ? PropertyGroupViewModel.Children : null;
|
public ObservableCollection<ViewModelBase>? Children => PropertyGroupViewModel.IsExpanded ? PropertyGroupViewModel.Children : null;
|
||||||
@ -43,6 +43,6 @@ public class TimelineGroupViewModel : ActivatableViewModelBase
|
|||||||
{
|
{
|
||||||
KeyframePositions = new ObservableCollection<double>(PropertyGroupViewModel
|
KeyframePositions = new ObservableCollection<double>(PropertyGroupViewModel
|
||||||
.GetAllKeyframeViewModels(false)
|
.GetAllKeyframeViewModels(false)
|
||||||
.Select(p => p.Position.TotalSeconds * _pixelsPerSecond));
|
.Select(p => p.Position.TotalSeconds * PixelsPerSecond));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -4,7 +4,7 @@
|
|||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||||
x:Class="Artemis.UI.Screens.ProfileEditor.Properties.Timeline.TimelinePropertyView">
|
x:Class="Artemis.UI.Screens.ProfileEditor.Properties.Timeline.TimelinePropertyView">
|
||||||
<Border Height="{DynamicResource RailsBorderHeight}" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource ButtonBorderBrush}">
|
<Border Height="29" BorderThickness="0,0,0,1" BorderBrush="{DynamicResource ButtonBorderBrush}">
|
||||||
<ItemsControl Items="{Binding KeyframeViewModels}">
|
<ItemsControl Items="{Binding KeyframeViewModels}">
|
||||||
<ItemsControl.ItemsPanel>
|
<ItemsControl.ItemsPanel>
|
||||||
<ItemsPanelTemplate>
|
<ItemsPanelTemplate>
|
||||||
@ -14,6 +14,7 @@
|
|||||||
<ItemsControl.Styles>
|
<ItemsControl.Styles>
|
||||||
<Style Selector="ItemsControl > ContentPresenter">
|
<Style Selector="ItemsControl > ContentPresenter">
|
||||||
<Setter Property="Canvas.Left" Value="{Binding X, TargetNullValue=0}" />
|
<Setter Property="Canvas.Left" Value="{Binding X, TargetNullValue=0}" />
|
||||||
|
<Setter Property="Canvas.Top" Value="9" />
|
||||||
</Style>
|
</Style>
|
||||||
</ItemsControl.Styles>
|
</ItemsControl.Styles>
|
||||||
</ItemsControl>
|
</ItemsControl>
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user