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

Merge branch 'development'

This commit is contained in:
Robert 2023-05-22 20:54:29 +02:00
commit 9cfa45972d
20 changed files with 119 additions and 123 deletions

View File

@ -43,9 +43,9 @@
<PackageReference Include="LiteDB" Version="5.0.16" /> <PackageReference Include="LiteDB" Version="5.0.16" />
<PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" /> <PackageReference Include="McMaster.NETCore.Plugins" Version="1.4.0" />
<PackageReference Include="Newtonsoft.Json" Version="13.0.1" /> <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
<PackageReference Include="RGB.NET.Core" Version="2.0.0-prerelease.53" /> <PackageReference Include="RGB.NET.Core" Version="2.0.0-prerelease.69" />
<PackageReference Include="RGB.NET.Layout" Version="2.0.0-prerelease.53" /> <PackageReference Include="RGB.NET.Layout" Version="2.0.0-prerelease.69" />
<PackageReference Include="RGB.NET.Presets" Version="2.0.0-prerelease.53" /> <PackageReference Include="RGB.NET.Presets" Version="2.0.0-prerelease.69" />
<PackageReference Include="Serilog" Version="2.12.0" /> <PackageReference Include="Serilog" Version="2.12.0" />
<PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" /> <PackageReference Include="Serilog.Sinks.Console" Version="4.1.0" />
<PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" /> <PackageReference Include="Serilog.Sinks.Debug" Version="2.0.0" />

View File

@ -396,7 +396,7 @@ internal class PluginManagementService : IPluginManagementService
List<Type> featureTypes; List<Type> featureTypes;
try try
{ {
featureTypes = plugin.Assembly.GetTypes().Where(t => typeof(PluginFeature).IsAssignableFrom(t)).ToList(); featureTypes = plugin.Assembly.GetTypes().Where(t => typeof(PluginFeature).IsAssignableFrom(t) && !t.IsAbstract).ToList();
} }
catch (ReflectionTypeLoadException e) catch (ReflectionTypeLoadException e)
{ {

View File

@ -20,7 +20,7 @@
<PackageReference Include="Material.Icons.Avalonia" Version="2.0.0-preview3" /> <PackageReference Include="Material.Icons.Avalonia" Version="2.0.0-preview3" />
<PackageReference Include="ReactiveUI" Version="18.4.26" /> <PackageReference Include="ReactiveUI" Version="18.4.26" />
<PackageReference Include="ReactiveUI.Validation" Version="3.1.7" /> <PackageReference Include="ReactiveUI.Validation" Version="3.1.7" />
<PackageReference Include="RGB.NET.Core" Version="2.0.0-prerelease.53" /> <PackageReference Include="RGB.NET.Core" Version="2.0.0-prerelease.69" />
<PackageReference Include="SkiaSharp" Version="2.88.3" /> <PackageReference Include="SkiaSharp" Version="2.88.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

View File

@ -1,6 +1,5 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel; using System.ComponentModel;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
@ -13,6 +12,10 @@ using Avalonia.LogicalTree;
using Avalonia.Media; using Avalonia.Media;
using Avalonia.Media.Imaging; using Avalonia.Media.Imaging;
using Avalonia.Threading; using Avalonia.Threading;
using RGB.NET.Core;
using Color = RGB.NET.Core.Color;
using Point = Avalonia.Point;
using Size = Avalonia.Size;
namespace Artemis.UI.Shared; namespace Artemis.UI.Shared;
@ -21,20 +24,20 @@ namespace Artemis.UI.Shared;
/// </summary> /// </summary>
public class DeviceVisualizer : Control public class DeviceVisualizer : Control
{ {
private const double UpdateFrameRate = 25.0; private const double UPDATE_FRAME_RATE = 25.0;
private readonly List<DeviceVisualizerLed> _deviceVisualizerLeds; private readonly List<DeviceVisualizerLed> _deviceVisualizerLeds;
private readonly DispatcherTimer _timer; private readonly DispatcherTimer _timer;
private Rect _deviceBounds; private Rect _deviceBounds;
private RenderTargetBitmap? _deviceImage; private RenderTargetBitmap? _deviceImage;
private List<DeviceVisualizerLed>? _dimmedLeds;
private List<DeviceVisualizerLed>? _highlightedLeds;
private ArtemisDevice? _oldDevice; private ArtemisDevice? _oldDevice;
private bool _loading;
private Color[] _previousState = Array.Empty<Color>();
/// <inheritdoc /> /// <inheritdoc />
public DeviceVisualizer() public DeviceVisualizer()
{ {
_timer = new DispatcherTimer(DispatcherPriority.Render) {Interval = TimeSpan.FromMilliseconds(1000.0 / UpdateFrameRate)}; _timer = new DispatcherTimer(DispatcherPriority.Background) {Interval = TimeSpan.FromMilliseconds(1000.0 / UPDATE_FRAME_RATE)};
_deviceVisualizerLeds = new List<DeviceVisualizerLed>(); _deviceVisualizerLeds = new List<DeviceVisualizerLed>();
PointerReleased += OnPointerReleased; PointerReleased += OnPointerReleased;
@ -77,7 +80,7 @@ public class DeviceVisualizer : Control
// Apply device scale // Apply device scale
using DrawingContext.PushedState scalePush = drawingContext.PushTransform(Matrix.CreateScale(Device.Scale, Device.Scale)); using DrawingContext.PushedState scalePush = drawingContext.PushTransform(Matrix.CreateScale(Device.Scale, Device.Scale));
foreach (DeviceVisualizerLed deviceVisualizerLed in _deviceVisualizerLeds) foreach (DeviceVisualizerLed deviceVisualizerLed in _deviceVisualizerLeds)
deviceVisualizerLed.RenderGeometry(drawingContext, false); deviceVisualizerLed.RenderGeometry(drawingContext);
} }
} }
finally finally
@ -112,6 +115,31 @@ public class DeviceVisualizer : Control
Clicked?.Invoke(this, e); Clicked?.Invoke(this, e);
} }
private bool IsDirty()
{
if (Device == null)
return false;
Color[] state = new Color[Device.RgbDevice.Count()];
bool difference = _previousState.Length != state.Length;
// Check all LEDs for differences and copy the colors to a new state
int index = 0;
foreach (Led led in Device.RgbDevice)
{
if (!difference && !led.Color.Equals(_previousState[index]))
difference = true;
state[index] = led.Color;
index++;
}
// Store the new state for next time
_previousState = state;
return difference;
}
private void Update() private void Update()
{ {
InvalidateVisual(); InvalidateVisual();
@ -131,7 +159,7 @@ public class DeviceVisualizer : Control
private void TimerOnTick(object? sender, EventArgs e) private void TimerOnTick(object? sender, EventArgs e)
{ {
if (ShowColors && IsVisible && Opacity > 0) if (IsDirty() && ShowColors && IsVisible && Opacity > 0)
Update(); Update();
} }
@ -200,23 +228,6 @@ public class DeviceVisualizer : Control
set => SetValue(ShowColorsProperty, value); set => SetValue(ShowColorsProperty, value);
} }
/// <summary>
/// Gets or sets a list of LEDs to highlight
/// </summary>
public static readonly StyledProperty<ObservableCollection<ArtemisLed>?> HighlightedLedsProperty =
AvaloniaProperty.Register<DeviceVisualizer, ObservableCollection<ArtemisLed>?>(nameof(HighlightedLeds));
private bool _loading;
/// <summary>
/// Gets or sets a list of LEDs to highlight
/// </summary>
public ObservableCollection<ArtemisLed>? HighlightedLeds
{
get => GetValue(HighlightedLedsProperty);
set => SetValue(HighlightedLedsProperty, value);
}
#endregion #endregion
#region Lifetime management #region Lifetime management
@ -254,9 +265,6 @@ public class DeviceVisualizer : Control
private void SetupForDevice() private void SetupForDevice()
{ {
_highlightedLeds = new List<DeviceVisualizerLed>();
_dimmedLeds = new List<DeviceVisualizerLed>();
lock (_deviceVisualizerLeds) lock (_deviceVisualizerLeds)
{ {
_deviceVisualizerLeds.Clear(); _deviceVisualizerLeds.Clear();
@ -305,7 +313,7 @@ public class DeviceVisualizer : Control
using DrawingContext context = renderTargetBitmap.CreateDrawingContext(); using DrawingContext context = renderTargetBitmap.CreateDrawingContext();
using Bitmap bitmap = new(device.Layout.Image.LocalPath); using Bitmap bitmap = new(device.Layout.Image.LocalPath);
using Bitmap scaledBitmap = bitmap.CreateScaledBitmap(renderTargetBitmap.PixelSize); using Bitmap scaledBitmap = bitmap.CreateScaledBitmap(renderTargetBitmap.PixelSize);
context.DrawImage(scaledBitmap, new Rect(scaledBitmap.Size)); context.DrawImage(scaledBitmap, new Rect(scaledBitmap.Size));
lock (_deviceVisualizerLeds) lock (_deviceVisualizerLeds)
{ {

View File

@ -20,13 +20,7 @@ internal class DeviceVisualizerLed
public DeviceVisualizerLed(ArtemisLed led) public DeviceVisualizerLed(ArtemisLed led)
{ {
Led = led; Led = led;
LedRect = new Rect(
Led.RgbLed.Location.X,
Led.RgbLed.Location.Y,
Led.RgbLed.Size.Width,
Led.RgbLed.Size.Height
);
_fillBrush = new SolidColorBrush(); _fillBrush = new SolidColorBrush();
_penBrush = new SolidColorBrush(); _penBrush = new SolidColorBrush();
_pen = new Pen(_penBrush) {LineJoin = PenLineJoin.Round}; _pen = new Pen(_penBrush) {LineJoin = PenLineJoin.Round};
@ -35,7 +29,6 @@ internal class DeviceVisualizerLed
} }
public ArtemisLed Led { get; } public ArtemisLed Led { get; }
public Rect LedRect { get; set; }
public Geometry? DisplayGeometry { get; private set; } public Geometry? DisplayGeometry { get; private set; }
public void DrawBitmap(DrawingContext drawingContext, double scale) public void DrawBitmap(DrawingContext drawingContext, double scale)
@ -58,7 +51,7 @@ internal class DeviceVisualizerLed
} }
} }
public void RenderGeometry(DrawingContext drawingContext, bool dimmed) public void RenderGeometry(DrawingContext drawingContext)
{ {
if (DisplayGeometry == null) if (DisplayGeometry == null)
return; return;
@ -66,17 +59,8 @@ internal class DeviceVisualizerLed
byte r = Led.RgbLed.Color.GetR(); byte r = Led.RgbLed.Color.GetR();
byte g = Led.RgbLed.Color.GetG(); byte g = Led.RgbLed.Color.GetG();
byte b = Led.RgbLed.Color.GetB(); byte b = Led.RgbLed.Color.GetB();
_fillBrush.Color = new Color(100, r, g, b);
if (dimmed) _penBrush.Color = new Color(255, r, g, b);
{
_fillBrush.Color = new Color(50, r, g, b);
_penBrush.Color = new Color(100, r, g, b);
}
else
{
_fillBrush.Color = new Color(100, r, g, b);
_penBrush.Color = new Color(255, r, g, b);
}
// Render the LED geometry // Render the LED geometry
drawingContext.DrawGeometry(_fillBrush, _pen, DisplayGeometry); drawingContext.DrawGeometry(_fillBrush, _pen, DisplayGeometry);

View File

@ -32,8 +32,7 @@
SimpleNumberFormat="{CompiledBinding $parent[sharedControls:DraggableNumberBox].SimpleNumberFormat}" SimpleNumberFormat="{CompiledBinding $parent[sharedControls:DraggableNumberBox].SimpleNumberFormat}"
attachedProperties:NumberBoxAssist.PrefixText="{CompiledBinding $parent[sharedControls:DraggableNumberBox].Prefix}" attachedProperties:NumberBoxAssist.PrefixText="{CompiledBinding $parent[sharedControls:DraggableNumberBox].Prefix}"
attachedProperties:NumberBoxAssist.SuffixText="{CompiledBinding $parent[sharedControls:DraggableNumberBox].Suffix}" attachedProperties:NumberBoxAssist.SuffixText="{CompiledBinding $parent[sharedControls:DraggableNumberBox].Suffix}"
HorizontalAlignment="{CompiledBinding $parent[sharedControls:DraggableNumberBox].HorizontalAlignment}" HorizontalAlignment="{CompiledBinding $parent[sharedControls:DraggableNumberBox].HorizontalAlignment}"/>
ValueChanged="NumberBox_OnValueChanged"/>
<Rectangle Name="DragCollider" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Fill="Transparent"></Rectangle> <Rectangle Name="DragCollider" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" Fill="Transparent"></Rectangle>
</Panel> </Panel>

View File

@ -4,7 +4,7 @@ using Avalonia.Controls;
using Avalonia.Data; using Avalonia.Data;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
using Avalonia.Markup.Xaml; using Avalonia.LogicalTree;
using Avalonia.VisualTree; using Avalonia.VisualTree;
using FluentAvalonia.Core; using FluentAvalonia.Core;
using FluentAvalonia.UI.Controls; using FluentAvalonia.UI.Controls;
@ -68,13 +68,12 @@ public partial class DraggableNumberBox : UserControl
public DraggableNumberBox() public DraggableNumberBox()
{ {
InitializeComponent(); InitializeComponent();
InnerNumberBox.Value = Value;
PointerPressed += OnPointerPressed; PointerPressed += OnPointerPressed;
PointerMoved += OnPointerMoved; PointerMoved += OnPointerMoved;
PointerReleased += OnPointerReleased; PointerReleased += OnPointerReleased;
PropertyChanged += OnPropertyChanged; PropertyChanged += OnPropertyChanged;
AddHandler(KeyUpEvent, HandleKeyUp, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble, true); AddHandler(KeyUpEvent, HandleKeyUp, RoutingStrategies.Direct | RoutingStrategies.Tunnel | RoutingStrategies.Bubble, true);
} }
@ -159,7 +158,22 @@ public partial class DraggableNumberBox : UserControl
/// Occurs when the user finishes dragging over the control. /// Occurs when the user finishes dragging over the control.
/// </summary> /// </summary>
public event TypedEventHandler<DraggableNumberBox, EventArgs>? DragFinished; public event TypedEventHandler<DraggableNumberBox, EventArgs>? DragFinished;
/// <inheritdoc />
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
InnerNumberBox.Value = Value;
InnerNumberBox.ValueChanged += InnerNumberBoxOnValueChanged;
base.OnAttachedToLogicalTree(e);
}
/// <inheritdoc />
protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
{
InnerNumberBox.ValueChanged -= InnerNumberBoxOnValueChanged;
base.OnDetachedFromLogicalTree(e);
}
private void SetNumberBoxValue(double value) private void SetNumberBoxValue(double value)
{ {
if (!(Math.Abs(InnerNumberBox.Value - Value) > 0.00001)) if (!(Math.Abs(InnerNumberBox.Value - Value) > 0.00001))
@ -243,14 +257,14 @@ public partial class DraggableNumberBox : UserControl
e.Handled = true; e.Handled = true;
} }
private void OnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) private void OnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e)
{ {
if (e.Property == ValueProperty) if (e.Property == ValueProperty)
SetNumberBoxValue(Value); SetNumberBoxValue(Value);
} }
private void NumberBox_OnValueChanged(NumberBox sender, NumberBoxValueChangedEventArgs args) private void InnerNumberBoxOnValueChanged(NumberBox sender, NumberBoxValueChangedEventArgs args)
{ {
if (_updating) if (_updating)
return; return;

View File

@ -78,6 +78,6 @@ public class OpenFileDialogBuilder
public async Task<string[]?> ShowAsync() public async Task<string[]?> ShowAsync()
{ {
IReadOnlyList<IStorageFile> files = await _parent.StorageProvider.OpenFilePickerAsync(_options); IReadOnlyList<IStorageFile> files = await _parent.StorageProvider.OpenFilePickerAsync(_options);
return files.Select(f => f.Path.LocalPath).ToArray(); return files.Count == 0 ? null : files.Select(f => f.Path.LocalPath).ToArray();
} }
} }

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Reactive.Linq; using System.Reactive.Linq;
@ -193,7 +194,7 @@ public abstract class PropertyInputViewModel<T> : PropertyInputViewModel
_updating = true; _updating = true;
// Avoid unnecessary UI updates and validator cycles // Avoid unnecessary UI updates and validator cycles
if (Equals(_inputValue, LayerProperty.CurrentValue)) if (EqualityComparer<T>.Default.Equals(_inputValue, LayerProperty.CurrentValue))
return; return;
// Override the input value // Override the input value

View File

@ -32,8 +32,8 @@
<PackageReference Include="Octopus.Octodiff" Version="2.0.261" /> <PackageReference Include="Octopus.Octodiff" Version="2.0.261" />
<PackageReference Include="ReactiveUI" Version="18.4.26" /> <PackageReference Include="ReactiveUI" Version="18.4.26" />
<PackageReference Include="ReactiveUI.Validation" Version="3.1.7" /> <PackageReference Include="ReactiveUI.Validation" Version="3.1.7" />
<PackageReference Include="RGB.NET.Core" Version="2.0.0-prerelease.53" /> <PackageReference Include="RGB.NET.Core" Version="2.0.0-prerelease.69" />
<PackageReference Include="RGB.NET.Layout" Version="2.0.0-prerelease.53" /> <PackageReference Include="RGB.NET.Layout" Version="2.0.0-prerelease.69" />
<PackageReference Include="SkiaSharp" Version="2.88.3" /> <PackageReference Include="SkiaSharp" Version="2.88.3" />
<PackageReference Include="Splat.DryIoc" Version="14.6.8" /> <PackageReference Include="Splat.DryIoc" Version="14.6.8" />
</ItemGroup> </ItemGroup>

View File

@ -30,12 +30,12 @@
</VisualBrush> </VisualBrush>
</Grid.Background> </Grid.Background>
<Grid Grid.Column="0" Name="DeviceDisplayGrid" PointerReleased="DeviceDisplayGrid_OnPointerReleased"> <Grid Grid.Column="0" Name="DeviceDisplayGrid" PointerReleased="DeviceDisplayGrid_OnPointerReleased">
<!-- No need to provide LEDs to highlight as LEDs are already physically highlighted -->
<shared:DeviceVisualizer Device="{CompiledBinding Device}" <shared:DeviceVisualizer Device="{CompiledBinding Device}"
HorizontalAlignment="Center" HorizontalAlignment="Center"
VerticalAlignment="Center" VerticalAlignment="Center"
ShowColors="True" ShowColors="True"
Margin="20" Margin="20"
RenderOptions.BitmapInterpolationMode="MediumQuality"
LedClicked="DeviceVisualizer_OnLedClicked" LedClicked="DeviceVisualizer_OnLedClicked"
Clicked="DeviceVisualizer_OnClicked" /> Clicked="DeviceVisualizer_OnClicked" />

View File

@ -18,7 +18,7 @@
Margin="10" Margin="10"
ShowColors="False" ShowColors="False"
Device="{CompiledBinding Device}" Device="{CompiledBinding Device}"
RenderOptions.BitmapInterpolationMode="HighQuality" /> RenderOptions.BitmapInterpolationMode="MediumQuality" />
<Button Grid.Row="0" <Button Grid.Row="0"
Classes="icon-button icon-button-large" Classes="icon-button icon-button-large"
VerticalAlignment="Bottom" VerticalAlignment="Bottom"

View File

@ -2,11 +2,11 @@
using System.Reactive; using System.Reactive;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Timers;
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Services; using Artemis.Core.Services;
using Artemis.UI.Shared; using Artemis.UI.Shared;
using Artemis.UI.Shared.Services.ProfileEditor; using Artemis.UI.Shared.Services.ProfileEditor;
using Avalonia.Threading;
using ReactiveUI; using ReactiveUI;
namespace Artemis.UI.Screens.ProfileEditor.Playback; namespace Artemis.UI.Screens.ProfileEditor.Playback;
@ -53,13 +53,17 @@ public class PlaybackViewModel : ActivatableViewModelBase
_formattedCurrentTime = _profileEditorService.Time.Select(t => $"{Math.Floor(t.TotalSeconds):00}.{t.Milliseconds:000}").ToProperty(this, vm => vm.FormattedCurrentTime).DisposeWith(d); _formattedCurrentTime = _profileEditorService.Time.Select(t => $"{Math.Floor(t.TotalSeconds):00}.{t.Milliseconds:000}").ToProperty(this, vm => vm.FormattedCurrentTime).DisposeWith(d);
_playing = _profileEditorService.Playing.ToProperty(this, vm => vm.Playing).DisposeWith(d); _playing = _profileEditorService.Playing.ToProperty(this, vm => vm.Playing).DisposeWith(d);
_keyBindingsEnabled = Shared.UI.KeyBindingsEnabled.ToProperty(this, vm => vm.KeyBindingsEnabled).DisposeWith(d); _keyBindingsEnabled = Shared.UI.KeyBindingsEnabled.ToProperty(this, vm => vm.KeyBindingsEnabled).DisposeWith(d);
// Update timer
Timer updateTimer = new(TimeSpan.FromMilliseconds(60.0 / 1000));
updateTimer.Elapsed += (_, _) => Update();
updateTimer.DisposeWith(d);
_profileEditorService.Playing.Subscribe(_ => _lastUpdate = DateTime.Now).DisposeWith(d);
_profileEditorService.Playing.Subscribe(p => updateTimer.Enabled = p).DisposeWith(d);
_lastUpdate = DateTime.MinValue; _lastUpdate = DateTime.MinValue;
DispatcherTimer updateTimer = new(TimeSpan.FromMilliseconds(60.0 / 1000), DispatcherPriority.Background, Update);
updateTimer.Start();
Disposable.Create(() => Disposable.Create(() =>
{ {
updateTimer.Stop();
_settingsService.GetSetting("ProfileEditor.RepeatTimeline", true).Value = _repeating && _repeatTimeline; _settingsService.GetSetting("ProfileEditor.RepeatTimeline", true).Value = _repeating && _repeatTimeline;
_settingsService.GetSetting("ProfileEditor.RepeatSegment", false).Value = _repeating && _repeatSegment; _settingsService.GetSetting("ProfileEditor.RepeatSegment", false).Value = _repeating && _repeatSegment;
}).DisposeWith(d); }).DisposeWith(d);
@ -206,13 +210,10 @@ public class PlaybackViewModel : ActivatableViewModelBase
return TimeSpan.Zero; return TimeSpan.Zero;
} }
private void Update(object? sender, EventArgs e) private void Update()
{ {
try try
{ {
if (!Playing)
return;
if (_lastUpdate == DateTime.MinValue) if (_lastUpdate == DateTime.MinValue)
_lastUpdate = DateTime.Now; _lastUpdate = DateTime.Now;

View File

@ -2,6 +2,7 @@
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Reactive.Linq; using System.Reactive.Linq;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Timers;
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Services; using Artemis.Core.Services;
using Artemis.UI.DryIoc.Factories; using Artemis.UI.DryIoc.Factories;
@ -50,20 +51,16 @@ public class DataBindingViewModel : ActivatableViewModelBase
.DisposeWith(d); .DisposeWith(d);
_profileEditorService.Playing.CombineLatest(_profileEditorService.SuspendedEditing).Subscribe(tuple => _playing = tuple.First || tuple.Second).DisposeWith(d); _profileEditorService.Playing.CombineLatest(_profileEditorService.SuspendedEditing).Subscribe(tuple => _playing = tuple.First || tuple.Second).DisposeWith(d);
DispatcherTimer updateTimer = new(TimeSpan.FromMilliseconds(25.0 / 1000), DispatcherPriority.Background, Update); Timer updateTimer = new(TimeSpan.FromMilliseconds(25.0 / 1000));
// TODO: Remove in favor of saving each time a node editor command is executed Timer saveTimer = new(TimeSpan.FromMinutes(2));
DispatcherTimer saveTimer = new(TimeSpan.FromMinutes(2), DispatcherPriority.Normal, Save);
updateTimer.Elapsed += (_, _) => Update();
saveTimer.Elapsed += (_, _) => Save();
updateTimer.Start(); updateTimer.Start();
saveTimer.Start(); saveTimer.Start();
Disposable.Create(() => updateTimer.DisposeWith(d);
{ saveTimer.DisposeWith(d);
updateTimer.Stop();
saveTimer.Stop();
_profileEditorService.SaveProfile();
}).DisposeWith(d);
}); });
} }
@ -97,7 +94,7 @@ public class DataBindingViewModel : ActivatableViewModelBase
} }
} }
private void Update(object? sender, EventArgs e) private void Update()
{ {
// If playing the data binding will already be updated, no need to do it here // If playing the data binding will already be updated, no need to do it here
if (_playing || !_alwaysApplyDataBindings.Value) if (_playing || !_alwaysApplyDataBindings.Value)
@ -106,7 +103,7 @@ public class DataBindingViewModel : ActivatableViewModelBase
LayerProperty?.UpdateDataBinding(); LayerProperty?.UpdateDataBinding();
} }
private void Save(object? sender, EventArgs e) private void Save()
{ {
if (!_editorOpen) if (!_editorOpen)
_profileEditorService.SaveProfile(); _profileEditorService.SaveProfile();

View File

@ -53,7 +53,7 @@
</ItemsControl.ItemsPanel> </ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate> <ItemsControl.ItemTemplate>
<DataTemplate DataType="core:ArtemisDevice"> <DataTemplate DataType="core:ArtemisDevice">
<shared:DeviceVisualizer Device="{CompiledBinding}" ShowColors="True" RenderOptions.BitmapInterpolationMode="HighQuality" /> <shared:DeviceVisualizer Device="{CompiledBinding}" ShowColors="True" RenderOptions.BitmapInterpolationMode="MediumQuality" />
</DataTemplate> </DataTemplate>
</ItemsControl.ItemTemplate> </ItemsControl.ItemTemplate>
</ItemsControl> </ItemsControl>

View File

@ -1,8 +1,8 @@
using System; using System;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Timers;
using Artemis.Core.Modules; using Artemis.Core.Modules;
using Artemis.UI.Shared; using Artemis.UI.Shared;
using Avalonia.Threading;
using Humanizer; using Humanizer;
using ReactiveUI; using ReactiveUI;
@ -13,7 +13,6 @@ public class ModuleActivationRequirementViewModel : ActivatableViewModelBase
private readonly IModuleActivationRequirement _activationRequirement; private readonly IModuleActivationRequirement _activationRequirement;
private string _requirementDescription; private string _requirementDescription;
private bool _requirementMet; private bool _requirementMet;
private DispatcherTimer? _updateTimer;
public ModuleActivationRequirementViewModel(IModuleActivationRequirement activationRequirement) public ModuleActivationRequirementViewModel(IModuleActivationRequirement activationRequirement)
{ {
@ -23,14 +22,10 @@ public class ModuleActivationRequirementViewModel : ActivatableViewModelBase
this.WhenActivated(d => this.WhenActivated(d =>
{ {
_updateTimer = new DispatcherTimer(TimeSpan.FromMilliseconds(500), DispatcherPriority.Background, Update); Timer updateTimer = new(TimeSpan.FromMilliseconds(500));
_updateTimer.Start(); updateTimer.Elapsed += (_, _) => Update();
updateTimer.Start();
Disposable.Create(() => updateTimer.DisposeWith(d);
{
_updateTimer?.Stop();
_updateTimer = null;
}).DisposeWith(d);
}); });
} }
@ -48,7 +43,7 @@ public class ModuleActivationRequirementViewModel : ActivatableViewModelBase
set => RaiseAndSetIfChanged(ref _requirementMet, value); set => RaiseAndSetIfChanged(ref _requirementMet, value);
} }
private void Update(object? sender, EventArgs e) private void Update()
{ {
RequirementDescription = _activationRequirement.GetUserFriendlyDescription(); RequirementDescription = _activationRequirement.GetUserFriendlyDescription();
RequirementMet = _activationRequirement.Evaluate(); RequirementMet = _activationRequirement.Evaluate();

View File

@ -9,7 +9,7 @@
x:DataType="surfaceEditor:ListDeviceViewModel"> x:DataType="surfaceEditor:ListDeviceViewModel">
<Grid ColumnDefinitions="Auto,*,Auto" RowDefinitions="*,*"> <Grid ColumnDefinitions="Auto,*,Auto" RowDefinitions="*,*">
<Border Grid.Column="0" Grid.RowSpan="2" Width="64" Height="50" Margin="0 0 10 0"> <Border Grid.Column="0" Grid.RowSpan="2" Width="64" Height="50" Margin="0 0 10 0">
<shared:DeviceVisualizer Device="{CompiledBinding Device}" ShowColors="True" VerticalAlignment="Center" HorizontalAlignment="Center"/> <shared:DeviceVisualizer Device="{CompiledBinding Device}" ShowColors="True" VerticalAlignment="Center" HorizontalAlignment="Center" RenderOptions.BitmapInterpolationMode="MediumQuality"/>
</Border> </Border>
<TextBlock Grid.Column="1" Grid.Row="0" Text="{CompiledBinding Device.RgbDevice.DeviceInfo.DeviceName}" VerticalAlignment="Bottom" /> <TextBlock Grid.Column="1" Grid.Row="0" Text="{CompiledBinding Device.RgbDevice.DeviceInfo.DeviceName}" VerticalAlignment="Bottom" />
<TextBlock Grid.Column="1" Grid.Row="1" Classes="subtitle" Text="{CompiledBinding Device.RgbDevice.DeviceInfo.Manufacturer}" VerticalAlignment="Top" /> <TextBlock Grid.Column="1" Grid.Row="1" Classes="subtitle" Text="{CompiledBinding Device.RgbDevice.DeviceInfo.Manufacturer}" VerticalAlignment="Top" />

View File

@ -27,7 +27,7 @@
</Style> </Style>
</Grid.Styles> </Grid.Styles>
<shared:DeviceVisualizer Device="{CompiledBinding Device}" ShowColors="True" RenderOptions.BitmapInterpolationMode="HighQuality"/> <shared:DeviceVisualizer Device="{CompiledBinding Device}" ShowColors="True" RenderOptions.BitmapInterpolationMode="MediumQuality"/>
<Border x:Name="SurfaceDeviceBorder" <Border x:Name="SurfaceDeviceBorder"
Classes="selection-border" Classes="selection-border"
Classes.selected="{CompiledBinding IsSelected}" Classes.selected="{CompiledBinding IsSelected}"

View File

@ -5,6 +5,7 @@ using System.IO;
using System.Reactive; using System.Reactive;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using System.Threading.Tasks; using System.Threading.Tasks;
using System.Timers;
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Services; using Artemis.Core.Services;
using Artemis.UI.DryIoc.Factories; using Artemis.UI.DryIoc.Factories;
@ -12,9 +13,7 @@ using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.NodeEditor; using Artemis.UI.Shared.Services.NodeEditor;
using Artemis.UI.Shared.Services.NodeEditor.Commands; using Artemis.UI.Shared.Services.NodeEditor.Commands;
using Avalonia; using Avalonia;
using Avalonia.Threading;
using DynamicData; using DynamicData;
using DynamicData.List;
using ReactiveUI; using ReactiveUI;
namespace Artemis.UI.Screens.VisualScripting; namespace Artemis.UI.Screens.VisualScripting;
@ -66,19 +65,17 @@ public class NodeScriptWindowViewModel : NodeScriptWindowViewModelBase
this.WhenActivated(d => this.WhenActivated(d =>
{ {
_keyBindingsEnabled = Shared.UI.KeyBindingsEnabled.ToProperty(this, vm => vm.KeyBindingsEnabled).DisposeWith(d); _keyBindingsEnabled = Shared.UI.KeyBindingsEnabled.ToProperty(this, vm => vm.KeyBindingsEnabled).DisposeWith(d);
DispatcherTimer updateTimer = new(TimeSpan.FromMilliseconds(25.0 / 1000), DispatcherPriority.Background, Update);
// TODO: Remove in favor of saving each time a node editor command is executed
DispatcherTimer saveTimer = new(TimeSpan.FromMinutes(2), DispatcherPriority.Background, Save);
Timer updateTimer = new(TimeSpan.FromMilliseconds(25.0 / 1000));
Timer saveTimer = new(TimeSpan.FromMinutes(2));
updateTimer.Elapsed += (_, _) => Update();
saveTimer.Elapsed += (_, _) => Save();
updateTimer.Start(); updateTimer.Start();
saveTimer.Start(); saveTimer.Start();
Disposable.Create(() => updateTimer.DisposeWith(d);
{ saveTimer.DisposeWith(d);
updateTimer.Stop();
saveTimer.Stop();
}).DisposeWith(d);
}); });
} }
@ -93,7 +90,7 @@ public class NodeScriptWindowViewModel : NodeScriptWindowViewModelBase
public ReactiveCommand<Unit, Unit> Export { get; } public ReactiveCommand<Unit, Unit> Export { get; }
public ReactiveCommand<Unit, Unit> Import { get; } public ReactiveCommand<Unit, Unit> Import { get; }
public bool KeyBindingsEnabled => _keyBindingsEnabled?.Value ?? false; public bool KeyBindingsEnabled => _keyBindingsEnabled?.Value ?? false;
public PluginSetting<bool> ShowDataModelValues => _settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false); public PluginSetting<bool> ShowDataModelValues => _settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false);
public PluginSetting<bool> ShowFullPaths => _settingsService.GetSetting("ProfileEditor.ShowFullPaths", false); public PluginSetting<bool> ShowFullPaths => _settingsService.GetSetting("ProfileEditor.ShowFullPaths", false);
public PluginSetting<bool> AlwaysShowValues => _settingsService.GetSetting("ProfileEditor.AlwaysShowValues", true); public PluginSetting<bool> AlwaysShowValues => _settingsService.GetSetting("ProfileEditor.AlwaysShowValues", true);
@ -157,7 +154,7 @@ public class NodeScriptWindowViewModel : NodeScriptWindowViewModelBase
.HavingFilter(f => f.WithExtension("json").WithName("Artemis node script")) .HavingFilter(f => f.WithExtension("json").WithName("Artemis node script"))
.ShowAsync(); .ShowAsync();
if (result == null) if (result == null || result.Length == 0)
return; return;
try try
@ -176,13 +173,13 @@ public class NodeScriptWindowViewModel : NodeScriptWindowViewModelBase
} }
} }
private void Update(object? sender, EventArgs e) private void Update()
{ {
if (!_pauseUpdate) if (!_pauseUpdate)
NodeScript.Run(); NodeScript.Run();
} }
private void Save(object? sender, EventArgs e) private void Save()
{ {
if (NodeScript.Context is Profile profile) if (NodeScript.Context is Profile profile)
_profileService.SaveProfile(profile, true); _profileService.SaveProfile(profile, true);

View File

@ -1,7 +1,6 @@
using System.Reactive.Disposables; using System.Reactive.Disposables;
using Artemis.Core; using Artemis.Core;
using Artemis.UI.Shared.VisualScripting; using Artemis.UI.Shared.VisualScripting;
using Avalonia.Threading;
using ReactiveUI; using ReactiveUI;
namespace Artemis.VisualScripting.Nodes.Static.Screens; namespace Artemis.VisualScripting.Nodes.Static.Screens;
@ -18,9 +17,10 @@ public class DisplayValueNodeCustomViewModel : CustomNodeViewModel
// Because the DisplayValueNode has no output it never evaluates, manually do so here // Because the DisplayValueNode has no output it never evaluates, manually do so here
this.WhenActivated(d => this.WhenActivated(d =>
{ {
DispatcherTimer updateTimer = new(TimeSpan.FromMilliseconds(25.0 / 1000), DispatcherPriority.Background, Update); System.Timers.Timer updateTimer = new(TimeSpan.FromMilliseconds(25.0 / 1000));
updateTimer.Elapsed += (_, _) => Update();
updateTimer.Start(); updateTimer.Start();
Disposable.Create(() => updateTimer.Stop()).DisposeWith(d); updateTimer.DisposeWith(d);
}); });
} }
@ -30,7 +30,7 @@ public class DisplayValueNodeCustomViewModel : CustomNodeViewModel
private set => this.RaiseAndSetIfChanged(ref _currentValue, value); private set => this.RaiseAndSetIfChanged(ref _currentValue, value);
} }
private void Update(object? sender, EventArgs e) private void Update()
{ {
try try
{ {