diff --git a/.github/workflows/docfx.yml b/.github/workflows/docfx.yml index 044774480..1f83763b9 100644 --- a/.github/workflows/docfx.yml +++ b/.github/workflows/docfx.yml @@ -18,13 +18,13 @@ jobs: with: dotnet-version: "7.0.x" - name: Setup DocFX - run: choco install docfx -y + run: dotnet tool update -g docfx - name: Build Core run: dotnet build src/Artemis.Core/Artemis.Core.csproj - name: Build UI.Shared run: dotnet build src/Artemis.UI.Shared/Artemis.UI.Shared.csproj - name: Build DocFX - run: docfx.exe docfx/docfx_project/docfx.json + run: docfx docfx/docfx_project/docfx.json - name: Upload to FTP uses: SamKirkland/FTP-Deploy-Action@4.3.2 with: diff --git a/docfx/docfx_project/docfx.json b/docfx/docfx_project/docfx.json index 525c27ace..003caa407 100644 --- a/docfx/docfx_project/docfx.json +++ b/docfx/docfx_project/docfx.json @@ -5,7 +5,7 @@ { "files": [ "Artemis.Core/bin/net7.0/Artemis.Core.dll", - "Artemis.UI.Shared/bin/net7.0/Artemis.UI.Shared.dll", + "Artemis.UI.Shared/bin/net7.0/Artemis.UI.Shared.dll" ], "src": "../../src" } diff --git a/src/Artemis.Core/Artemis.Core.csproj b/src/Artemis.Core/Artemis.Core.csproj index ed6e16421..33d2a5382 100644 --- a/src/Artemis.Core/Artemis.Core.csproj +++ b/src/Artemis.Core/Artemis.Core.csproj @@ -43,9 +43,9 @@ - - - + + + diff --git a/src/Artemis.UI.Linux/Artemis.UI.Linux.csproj b/src/Artemis.UI.Linux/Artemis.UI.Linux.csproj index 9607a10d8..21c5abd88 100644 --- a/src/Artemis.UI.Linux/Artemis.UI.Linux.csproj +++ b/src/Artemis.UI.Linux/Artemis.UI.Linux.csproj @@ -16,11 +16,11 @@ - - + + - - + + diff --git a/src/Artemis.UI.MacOS/Artemis.UI.MacOS.csproj b/src/Artemis.UI.MacOS/Artemis.UI.MacOS.csproj index e674a2ad6..9e2fc0938 100644 --- a/src/Artemis.UI.MacOS/Artemis.UI.MacOS.csproj +++ b/src/Artemis.UI.MacOS/Artemis.UI.MacOS.csproj @@ -15,11 +15,11 @@ - - + + - - + + diff --git a/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj b/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj index 0c4439627..3b69f3087 100644 --- a/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj +++ b/src/Artemis.UI.Shared/Artemis.UI.Shared.csproj @@ -10,17 +10,17 @@ - + - - - + + + - - + + - + diff --git a/src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs b/src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs index eca232ba4..80c72b0a5 100644 --- a/src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs +++ b/src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs @@ -1,9 +1,10 @@ -using System; +using System; using System.Collections.Generic; using System.ComponentModel; using System.IO; using System.Linq; using Artemis.Core; +using Artemis.Core.Services; using Artemis.UI.Shared.Events; using Avalonia; using Avalonia.Controls; @@ -13,6 +14,7 @@ using Avalonia.Media; using Avalonia.Media.Imaging; using Avalonia.Threading; using RGB.NET.Core; +using DryIoc; using Color = RGB.NET.Core.Color; using Point = Avalonia.Point; using Size = Avalonia.Size; @@ -24,20 +26,19 @@ namespace Artemis.UI.Shared; /// public class DeviceVisualizer : Control { - private const double UPDATE_FRAME_RATE = 25.0; + private readonly ICoreService _coreService; private readonly List _deviceVisualizerLeds; - private readonly DispatcherTimer _timer; private Rect _deviceBounds; private RenderTargetBitmap? _deviceImage; private ArtemisDevice? _oldDevice; private bool _loading; private Color[] _previousState = Array.Empty(); - + /// public DeviceVisualizer() { - _timer = new DispatcherTimer(DispatcherPriority.Background) {Interval = TimeSpan.FromMilliseconds(1000.0 / UPDATE_FRAME_RATE)}; + _coreService = UI.Locator.Resolve(); _deviceVisualizerLeds = new List(); PointerReleased += OnPointerReleased; @@ -120,23 +121,26 @@ public class DeviceVisualizer : Control if (Device == null) return false; - Color[] state = new Color[Device.RgbDevice.Count()]; - bool difference = _previousState.Length != state.Length; + bool difference = false; + + int newLedCount = Device.RgbDevice.Count(); + if (_previousState.Length != newLedCount) + { + _previousState = new Color[newLedCount]; + difference = true; + } // 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])) + if (_previousState[index] != led.Color) difference = true; - state[index] = led.Color; + _previousState[index] = led.Color; index++; } - // Store the new state for next time - _previousState = state; - return difference; } @@ -156,11 +160,14 @@ public class DeviceVisualizer : Control return geometry.Bounds; } - - private void TimerOnTick(object? sender, EventArgs e) + + private void OnFrameRendered(object? sender, FrameRenderedEventArgs e) { - if (IsDirty() && ShowColors && IsVisible && Opacity > 0) - Update(); + Dispatcher.UIThread.Post(() => + { + if (ShowColors && IsVisible && Opacity > 0 && IsDirty()) + Update(); + }, DispatcherPriority.Background); } private void OnPointerReleased(object? sender, PointerReleasedEventArgs e) @@ -250,16 +257,16 @@ public class DeviceVisualizer : Control /// protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) { - _timer.Start(); - _timer.Tick += TimerOnTick; + _coreService.FrameRendered += OnFrameRendered; + base.OnAttachedToLogicalTree(e); } /// protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e) { - _timer.Stop(); - _timer.Tick -= TimerOnTick; + _coreService.FrameRendered -= OnFrameRendered; + base.OnDetachedFromLogicalTree(e); } diff --git a/src/Artemis.UI.Shared/Controls/DraggableNumberBox.axaml b/src/Artemis.UI.Shared/Controls/DraggableNumberBox.axaml index 0c571239e..5802bd188 100644 --- a/src/Artemis.UI.Shared/Controls/DraggableNumberBox.axaml +++ b/src/Artemis.UI.Shared/Controls/DraggableNumberBox.axaml @@ -6,25 +6,27 @@ xmlns:sharedControls="clr-namespace:Artemis.UI.Shared.Controls" xmlns:attachedProperties="clr-namespace:Artemis.UI.Shared.AttachedProperties" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" - x:Class="Artemis.UI.Shared.Controls.DraggableNumberBox"> + x:Class="Artemis.UI.Shared.Controls.DraggableNumberBox" + Focusable="True"> - - - - + { UpdateDisplayTextBox(); @@ -78,7 +79,19 @@ public partial class HotkeyBox : UserControl private void InputServiceOnKeyboardKeyUp(object? sender, ArtemisKeyboardKeyEventArgs e) { if (e.Modifiers == KeyboardModifierKey.None) - Dispatcher.UIThread.Post(() => FocusManager.Instance?.Focus(null)); + Dispatcher.UIThread.Post(ClearFocus); + } + + private void ClearFocus() + { + InputElement? element = this.FindAncestorOfType(); + if (element == null) + return; + + bool wasFocusable = element.Focusable; + element.Focusable = true; + element.Focus(); + element.Focusable = wasFocusable; } private void UpdateDisplayTextBox() @@ -96,7 +109,7 @@ public partial class HotkeyBox : UserControl private void Button_OnClick(object? sender, RoutedEventArgs e) { Hotkey = null; - FocusManager.Instance?.Focus(null); + ClearFocus(); UpdateDisplayTextBox(); } diff --git a/src/Artemis.UI.Shared/ReactiveAppWindow.cs b/src/Artemis.UI.Shared/ReactiveAppWindow.cs index 58f4ad820..a751f4ee6 100644 --- a/src/Artemis.UI.Shared/ReactiveAppWindow.cs +++ b/src/Artemis.UI.Shared/ReactiveAppWindow.cs @@ -48,7 +48,7 @@ public class ReactiveAppWindow : AppWindow, IViewFor whe return; TransparencyBackgroundFallback = Brushes.Transparent; - TransparencyLevelHint = WindowTransparencyLevel.Mica; + TransparencyLevelHint = new[] {WindowTransparencyLevel.Mica}; TryEnableMicaEffect(); } diff --git a/src/Artemis.UI.Shared/Styles/Border.axaml b/src/Artemis.UI.Shared/Styles/Border.axaml index afcd9dee8..d753809a0 100644 --- a/src/Artemis.UI.Shared/Styles/Border.axaml +++ b/src/Artemis.UI.Shared/Styles/Border.axaml @@ -10,6 +10,15 @@ I'm in a panel yo! I'm in a panel yo! + + I'm in a panel yo! + + + + + I'm in a panel yo! + + I'm in a panel yo! @@ -50,4 +59,23 @@ + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Utilities.cs b/src/Artemis.UI.Shared/Utilities.cs index cb2d58992..832e07b75 100644 --- a/src/Artemis.UI.Shared/Utilities.cs +++ b/src/Artemis.UI.Shared/Utilities.cs @@ -1,7 +1,5 @@ using System; -using System.ComponentModel; using System.Reactive.Linq; -using System.Reactive.Subjects; using Avalonia.Controls; using Avalonia.Input; using Avalonia.Input.Platform; @@ -14,12 +12,9 @@ namespace Artemis.UI.Shared; /// public static class UI { - private static readonly BehaviorSubject KeyBindingsEnabledSubject = new(false); - static UI() { - if (KeyboardDevice.Instance != null) - KeyboardDevice.Instance.PropertyChanged += InstanceOnPropertyChanged; + KeyBindingsEnabled = InputElement.GotFocusEvent.Raised.Select(e => e.Item2.Source is not TextBox).StartWith(true); } /// @@ -35,15 +30,5 @@ public static class UI /// /// Gets a boolean indicating whether hotkeys are to be disabled. /// - public static IObservable KeyBindingsEnabled { get; } = KeyBindingsEnabledSubject.AsObservable(); - - private static void InstanceOnPropertyChanged(object? sender, PropertyChangedEventArgs e) - { - if (KeyboardDevice.Instance == null || e.PropertyName != nameof(KeyboardDevice.FocusedElement)) - return; - - bool enabled = KeyboardDevice.Instance.FocusedElement is not TextBox; - if (KeyBindingsEnabledSubject.Value != enabled) - KeyBindingsEnabledSubject.OnNext(enabled); - } + public static IObservable KeyBindingsEnabled { get; } } \ No newline at end of file diff --git a/src/Artemis.UI.Windows/Artemis.UI.Windows.csproj b/src/Artemis.UI.Windows/Artemis.UI.Windows.csproj index bdea0536c..0110ec37e 100644 --- a/src/Artemis.UI.Windows/Artemis.UI.Windows.csproj +++ b/src/Artemis.UI.Windows/Artemis.UI.Windows.csproj @@ -1,4 +1,4 @@ - + WinExe net7.0-windows10.0.17763.0 @@ -21,15 +21,15 @@ - - + + - - - + + + - + diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj index f30f7879f..54e584d67 100644 --- a/src/Artemis.UI/Artemis.UI.csproj +++ b/src/Artemis.UI/Artemis.UI.csproj @@ -16,25 +16,25 @@ - - - + + + - - - + + + - + - - + + - - + + @@ -42,27 +42,4 @@ - - - - UpdatingTabView.axaml - Code - - - UpdatingTabView.axaml - Code - - - PluginFeatureView.axaml - Code - - - PluginPrerequisiteActionView.axaml - Code - - - PluginPrerequisiteView.axaml - Code - - \ No newline at end of file diff --git a/src/Artemis.UI/Behaviors/SimpleContextDragBehavior.cs b/src/Artemis.UI/Behaviors/SimpleContextDragBehavior.cs index bd3845bfa..b23346427 100644 --- a/src/Artemis.UI/Behaviors/SimpleContextDragBehavior.cs +++ b/src/Artemis.UI/Behaviors/SimpleContextDragBehavior.cs @@ -103,8 +103,9 @@ public class SimpleContextDragBehavior : Behavior private void AssociatedObject_PointerPressed(object? sender, PointerPressedEventArgs e) { + IFocusManager? focusManager = TopLevel.GetTopLevel(AssociatedObject)?.FocusManager; PointerPointProperties properties = e.GetCurrentPoint(AssociatedObject).Properties; - if (!properties.IsLeftButtonPressed || FocusManager.Instance?.Current is TextBox) + if (!properties.IsLeftButtonPressed || focusManager?.GetFocusedElement() is TextBox) return; if (e.Source is not Control control || AssociatedObject?.DataContext != control.DataContext) return; @@ -130,8 +131,9 @@ public class SimpleContextDragBehavior : Behavior private async void AssociatedObject_PointerMoved(object? sender, PointerEventArgs e) { + IFocusManager? focusManager = TopLevel.GetTopLevel(AssociatedObject)?.FocusManager; PointerPointProperties properties = e.GetCurrentPoint(AssociatedObject).Properties; - if (!properties.IsLeftButtonPressed || FocusManager.Instance?.Current is TextBox) + if (!properties.IsLeftButtonPressed || focusManager?.GetFocusedElement() is TextBox) return; if (_triggerEvent is null) diff --git a/src/Artemis.UI/DefaultTypes/PropertyInput/StringPropertyInputView.axaml.cs b/src/Artemis.UI/DefaultTypes/PropertyInput/StringPropertyInputView.axaml.cs index 1ef4838a8..9063787d5 100644 --- a/src/Artemis.UI/DefaultTypes/PropertyInput/StringPropertyInputView.axaml.cs +++ b/src/Artemis.UI/DefaultTypes/PropertyInput/StringPropertyInputView.axaml.cs @@ -1,5 +1,4 @@ using Avalonia.Input; -using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; namespace Artemis.UI.DefaultTypes.PropertyInput; @@ -16,6 +15,6 @@ public partial class StringPropertyInputView : ReactiveUserControl selectedLeds); InputMappingsTabViewModel InputMappingsTabViewModel(ArtemisDevice device, ObservableCollection selectedLeds); + DeviceGeneralTabViewModel DeviceGeneralTabViewModel(ArtemisDevice device); } public class DeviceFactory : IDeviceVmFactory { @@ -68,16 +69,11 @@ public class DeviceFactory : IDeviceVmFactory return _container.Resolve(new object[] { device }); } - public DevicePropertiesTabViewModel DevicePropertiesTabViewModel(ArtemisDevice device) + public DeviceLayoutTabViewModel DeviceLayoutTabViewModel(ArtemisDevice device) { - return _container.Resolve(new object[] { device }); + return _container.Resolve(new object[] { device }); } - - public DeviceInfoTabViewModel DeviceInfoTabViewModel(ArtemisDevice device) - { - return _container.Resolve(new object[] { device }); - } - + public DeviceLedsTabViewModel DeviceLedsTabViewModel(ArtemisDevice device, ObservableCollection selectedLeds) { return _container.Resolve(new object[] { device, selectedLeds }); @@ -87,6 +83,11 @@ public class DeviceFactory : IDeviceVmFactory { return _container.Resolve(new object[] { device, selectedLeds }); } + + public DeviceGeneralTabViewModel DeviceGeneralTabViewModel(ArtemisDevice device) + { + return _container.Resolve(new object[] { device }); + } } public interface ISettingsVmFactory : IVmFactory diff --git a/src/Artemis.UI/Screens/Debugger/Tabs/Performance/PerformanceDebugView.axaml b/src/Artemis.UI/Screens/Debugger/Tabs/Performance/PerformanceDebugView.axaml index af60e504b..c6b2108fc 100644 --- a/src/Artemis.UI/Screens/Debugger/Tabs/Performance/PerformanceDebugView.axaml +++ b/src/Artemis.UI/Screens/Debugger/Tabs/Performance/PerformanceDebugView.axaml @@ -17,7 +17,7 @@ These performance stats are rather basic, for advanced performance profiling check out the wiki. - + JetBrains Profiling Guide diff --git a/src/Artemis.UI/Screens/Device/DevicePropertiesView.axaml b/src/Artemis.UI/Screens/Device/DevicePropertiesView.axaml index 22b63510e..2d0bccd94 100644 --- a/src/Artemis.UI/Screens/Device/DevicePropertiesView.axaml +++ b/src/Artemis.UI/Screens/Device/DevicePropertiesView.axaml @@ -1,58 +1,59 @@ + 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:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared" + xmlns:device="clr-namespace:Artemis.UI.Screens.Device" + xmlns:windowing="clr-namespace:FluentAvalonia.UI.Windowing;assembly=FluentAvalonia" + mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="800" + x:Class="Artemis.UI.Screens.Device.DevicePropertiesView" + x:DataType="device:DevicePropertiesViewModel" + Icon="/Assets/Images/Logo/application.ico" + Title="Artemis | Device Properties" + WindowStartupLocation="CenterOwner" + Width="1400" + Height="800"> - - - - - - - - - - - - - - + + + + + + + + + + + + + + + - - - - - + + + + + + - + @@ -69,6 +70,6 @@ - + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Device/DevicePropertiesViewModel.cs b/src/Artemis.UI/Screens/Device/DevicePropertiesViewModel.cs index 87ee3ae20..2c9cf056a 100644 --- a/src/Artemis.UI/Screens/Device/DevicePropertiesViewModel.cs +++ b/src/Artemis.UI/Screens/Device/DevicePropertiesViewModel.cs @@ -64,8 +64,8 @@ public class DevicePropertiesViewModel : DialogViewModelBase private void AddTabs() { - Tabs.Add(_deviceVmFactory.DevicePropertiesTabViewModel(Device)); - Tabs.Add(_deviceVmFactory.DeviceInfoTabViewModel(Device)); + Tabs.Add(_deviceVmFactory.DeviceGeneralTabViewModel(Device)); + Tabs.Add(_deviceVmFactory.DeviceLayoutTabViewModel(Device)); if (Device.DeviceType == RGBDeviceType.Keyboard) Tabs.Add(_deviceVmFactory.InputMappingsTabViewModel(Device, SelectedLeds)); Tabs.Add(_deviceVmFactory.DeviceLedsTabViewModel(Device, SelectedLeds)); diff --git a/src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabView.axaml b/src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabView.axaml new file mode 100644 index 000000000..5512743c0 --- /dev/null +++ b/src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabView.axaml @@ -0,0 +1,210 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + X-coordinate + + mm + + Y-coordinate + + mm + + Scale + + times + + Rotation + + deg + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabView.axaml.cs b/src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabView.axaml.cs new file mode 100644 index 000000000..8c4dff8b0 --- /dev/null +++ b/src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabView.axaml.cs @@ -0,0 +1,11 @@ +using Avalonia.Controls; +using Avalonia.ReactiveUI; + +namespace Artemis.UI.Screens.Device; +public partial class DeviceGeneralTabView : ReactiveUserControl +{ + public DeviceGeneralTabView() + { + InitializeComponent(); + } +} diff --git a/src/Artemis.UI/Screens/Device/Tabs/DevicePropertiesTabViewModel.cs b/src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabViewModel.cs similarity index 74% rename from src/Artemis.UI/Screens/Device/Tabs/DevicePropertiesTabViewModel.cs rename to src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabViewModel.cs index da3ac2fb3..40945c443 100644 --- a/src/Artemis.UI/Screens/Device/Tabs/DevicePropertiesTabViewModel.cs +++ b/src/Artemis.UI/Screens/Device/Tabs/DeviceGeneralTabViewModel.cs @@ -1,53 +1,57 @@ -using System; +using Artemis.UI.Shared; +using Artemis.UI.Shared; +using System; using System.Collections.Generic; using System.ComponentModel; +using System.Linq; using System.Reactive.Disposables; +using System.Text; +using System.Threading; using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Services; -using Artemis.UI.Shared; using Artemis.UI.Shared.Services; -using Artemis.UI.Shared.Services.Builders; using ReactiveUI; +using RGB.NET.Core; using SkiaSharp; namespace Artemis.UI.Screens.Device; -public class DevicePropertiesTabViewModel : ActivatableViewModelBase +public class DeviceGeneralTabViewModel : ActivatableViewModelBase { - private readonly List _categories; private readonly ICoreService _coreService; + private readonly IRgbService _rgbService; + private readonly IWindowService _windowService; + private readonly List _categories; + private readonly float _initialBlueScale; private readonly float _initialGreenScale; private readonly float _initialRedScale; - private readonly INotificationService _notificationService; - private readonly IRgbService _rgbService; - private readonly IWindowService _windowService; - private float _blueScale; - private SKColor _currentColor; - private bool _displayOnDevices; - private float _greenScale; - private float _redScale; + private int _rotation; private float _scale; private int _x; private int _y; - public DevicePropertiesTabViewModel(ArtemisDevice device, ICoreService coreService, IRgbService rgbService, IWindowService windowService, INotificationService notificationService) + private float _redScale; + private float _greenScale; + private float _blueScale; + private SKColor _currentColor; + private bool _displayOnDevices; + + public DeviceGeneralTabViewModel(ArtemisDevice device, ICoreService coreService, IRgbService rgbService, IWindowService windowService) { _coreService = coreService; _rgbService = rgbService; _windowService = windowService; - _notificationService = notificationService; _categories = new List(device.Categories); Device = device; - DisplayName = "Properties"; - - X = (int) Device.X; - Y = (int) Device.Y; + DisplayName = "General"; + X = (int)Device.X; + Y = (int)Device.Y; Scale = Device.Scale; - Rotation = (int) Device.Rotation; + Rotation = (int)Device.Rotation; RedScale = Device.RedScale * 100f; GreenScale = Device.GreenScale * 100f; BlueScale = Device.BlueScale * 100f; @@ -69,10 +73,13 @@ public class DevicePropertiesTabViewModel : ActivatableViewModelBase { _coreService.FrameRendering -= OnFrameRendering; Device.PropertyChanged -= DeviceOnPropertyChanged; + Apply(); }).DisposeWith(d); }); } + public bool RequiresManualSetup => !Device.DeviceProvider.CanDetectPhysicalLayout || !Device.DeviceProvider.CanDetectLogicalLayout; + public ArtemisDevice Device { get; } public int X @@ -99,6 +106,38 @@ public class DevicePropertiesTabViewModel : ActivatableViewModelBase set => RaiseAndSetIfChanged(ref _rotation, value); } + public bool IsKeyboard => Device.DeviceType == RGBDeviceType.Keyboard; + + public bool HasDeskCategory + { + get => GetCategory(DeviceCategory.Desk); + set => SetCategory(DeviceCategory.Desk, value); + } + + public bool HasMonitorCategory + { + get => GetCategory(DeviceCategory.Monitor); + set => SetCategory(DeviceCategory.Monitor, value); + } + + public bool HasCaseCategory + { + get => GetCategory(DeviceCategory.Case); + set => SetCategory(DeviceCategory.Case, value); + } + + public bool HasRoomCategory + { + get => GetCategory(DeviceCategory.Room); + set => SetCategory(DeviceCategory.Room, value); + } + + public bool HasPeripheralsCategory + { + get => GetCategory(DeviceCategory.Peripherals); + set => SetCategory(DeviceCategory.Peripherals, value); + } + public float RedScale { get => _redScale; @@ -129,72 +168,19 @@ public class DevicePropertiesTabViewModel : ActivatableViewModelBase set => RaiseAndSetIfChanged(ref _displayOnDevices, value); } - // This solution won't scale well but I don't expect there to be many more categories. - // If for some reason there will be, dynamically creating a view model per category may be more appropriate - public bool HasDeskCategory + private bool GetCategory(DeviceCategory category) { - get => GetCategory(DeviceCategory.Desk); - set => SetCategory(DeviceCategory.Desk, value); + return _categories.Contains(category); } - public bool HasMonitorCategory + private void SetCategory(DeviceCategory category, bool value) { - get => GetCategory(DeviceCategory.Monitor); - set => SetCategory(DeviceCategory.Monitor, value); - } + if (value && !_categories.Contains(category)) + _categories.Add(category); + else if (!value) + _categories.Remove(category); - public bool HasCaseCategory - { - get => GetCategory(DeviceCategory.Case); - set => SetCategory(DeviceCategory.Case, value); - } - - public bool HasRoomCategory - { - get => GetCategory(DeviceCategory.Room); - set => SetCategory(DeviceCategory.Room, value); - } - - public bool HasPeripheralsCategory - { - get => GetCategory(DeviceCategory.Peripherals); - set => SetCategory(DeviceCategory.Peripherals, value); - } - - public bool RequiresManualSetup => !Device.DeviceProvider.CanDetectPhysicalLayout || !Device.DeviceProvider.CanDetectLogicalLayout; - - public void ApplyScaling() - { - Device.RedScale = RedScale / 100f; - Device.GreenScale = GreenScale / 100f; - Device.BlueScale = BlueScale / 100f; - - _rgbService.FlushLeds = true; - } - - public void ClearCustomLayout() - { - Device.CustomLayoutPath = null; - _notificationService.CreateNotification() - .WithMessage("Cleared imported layout.") - .WithSeverity(NotificationSeverity.Informational); - } - - public async Task BrowseCustomLayout() - { - string[]? files = await _windowService.CreateOpenFileDialog() - .WithTitle("Select device layout file") - .HavingFilter(f => f.WithName("Layout files").WithExtension("xml")) - .ShowAsync(); - - if (files?.Length > 0) - { - Device.CustomLayoutPath = files[0]; - _notificationService.CreateNotification() - .WithTitle("Imported layout") - .WithMessage($"File loaded from {files[0]}") - .WithSeverity(NotificationSeverity.Informational); - } + this.RaisePropertyChanged($"Has{category}Category"); } public async Task RestartSetup() @@ -211,12 +197,12 @@ public class DevicePropertiesTabViewModel : ActivatableViewModelBase _rgbService.ApplyBestDeviceLayout(Device); } - public async Task Apply() + private void Apply() { // TODO: Validation _coreService.ProfileRenderingDisabled = true; - await Task.Delay(100); + Thread.Sleep(100); Device.X = X; Device.Y = Y; @@ -234,40 +220,28 @@ public class DevicePropertiesTabViewModel : ActivatableViewModelBase _coreService.ProfileRenderingDisabled = false; } - public void Reset() + public void ApplyScaling() { - HasDeskCategory = Device.Categories.Contains(DeviceCategory.Desk); - HasMonitorCategory = Device.Categories.Contains(DeviceCategory.Monitor); - HasCaseCategory = Device.Categories.Contains(DeviceCategory.Case); - HasRoomCategory = Device.Categories.Contains(DeviceCategory.Room); - HasPeripheralsCategory = Device.Categories.Contains(DeviceCategory.Peripherals); + Device.RedScale = RedScale / 100f; + Device.GreenScale = GreenScale / 100f; + Device.BlueScale = BlueScale / 100f; + _rgbService.FlushLeds = true; + } + + public void ResetScaling() + { RedScale = _initialRedScale * 100; GreenScale = _initialGreenScale * 100; BlueScale = _initialBlueScale * 100; } - private bool GetCategory(DeviceCategory category) - { - return _categories.Contains(category); - } - - private void SetCategory(DeviceCategory category, bool value) - { - if (value && !_categories.Contains(category)) - _categories.Add(category); - else if (!value) - _categories.Remove(category); - - this.RaisePropertyChanged($"Has{category}Category"); - } - private void OnFrameRendering(object? sender, FrameRenderingEventArgs e) { - if (!_displayOnDevices) + if (!DisplayOnDevices) return; - using SKPaint overlayPaint = new() {Color = CurrentColor}; + using SKPaint overlayPaint = new() { Color = CurrentColor }; e.Canvas.DrawRect(0, 0, e.Canvas.LocalClipBounds.Width, e.Canvas.LocalClipBounds.Height, overlayPaint); } diff --git a/src/Artemis.UI/Screens/Device/Tabs/DeviceInfoTabView.axaml b/src/Artemis.UI/Screens/Device/Tabs/DeviceInfoTabView.axaml deleted file mode 100644 index 1cb69cd13..000000000 --- a/src/Artemis.UI/Screens/Device/Tabs/DeviceInfoTabView.axaml +++ /dev/null @@ -1,88 +0,0 @@ - - - - - - - Device name - - - - Manufacturer - - - - - Device type - - - - - Physical layout - - - - - - - - Size (1px = 1mm) - - - - Location (1px = 1mm) - - - - Rotation (degrees) - - - - - Logical layout - - - - - - - - - - Default layout file path - - - - - - - Image file path - - - - - - - - - \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Device/Tabs/DeviceInfoTabViewModel.cs b/src/Artemis.UI/Screens/Device/Tabs/DeviceInfoTabViewModel.cs deleted file mode 100644 index 8ca43ad00..000000000 --- a/src/Artemis.UI/Screens/Device/Tabs/DeviceInfoTabViewModel.cs +++ /dev/null @@ -1,29 +0,0 @@ -using System.Threading.Tasks; -using Artemis.Core; -using Artemis.UI.Shared; -using Artemis.UI.Shared.Services; -using Avalonia; -using Avalonia.Controls; -using RGB.NET.Core; - -namespace Artemis.UI.Screens.Device; - -public class DeviceInfoTabViewModel : ActivatableViewModelBase -{ - private readonly INotificationService _notificationService; - - public DeviceInfoTabViewModel(ArtemisDevice device, INotificationService notificationService) - { - _notificationService = notificationService; - - Device = device; - DisplayName = "Info"; - - DefaultLayoutPath = Device.DeviceProvider.LoadLayout(Device).FilePath; - } - - public bool IsKeyboard => Device.DeviceType == RGBDeviceType.Keyboard; - public ArtemisDevice Device { get; } - - public string DefaultLayoutPath { get; } -} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Device/Tabs/DeviceLayoutTabView.axaml b/src/Artemis.UI/Screens/Device/Tabs/DeviceLayoutTabView.axaml new file mode 100644 index 000000000..d73cd4e43 --- /dev/null +++ b/src/Artemis.UI/Screens/Device/Tabs/DeviceLayoutTabView.axaml @@ -0,0 +1,89 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - Learn more about layouts on the wiki - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Device/Tabs/DevicePropertiesTabView.axaml.cs b/src/Artemis.UI/Screens/Device/Tabs/DevicePropertiesTabView.axaml.cs deleted file mode 100644 index f71b14155..000000000 --- a/src/Artemis.UI/Screens/Device/Tabs/DevicePropertiesTabView.axaml.cs +++ /dev/null @@ -1,19 +0,0 @@ -using Avalonia.Input; -using Avalonia.Markup.Xaml; -using Avalonia.ReactiveUI; - -namespace Artemis.UI.Screens.Device; - -public partial class DevicePropertiesTabView : ReactiveUserControl -{ - public DevicePropertiesTabView() - { - InitializeComponent(); - } - - - private void InputElement_OnPointerReleased(object? sender, PointerReleasedEventArgs e) - { - ViewModel?.BrowseCustomLayout(); - } -} \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Home/HomeView.axaml b/src/Artemis.UI/Screens/Home/HomeView.axaml index 2ce2016a0..0dd0458e4 100644 --- a/src/Artemis.UI/Screens/Home/HomeView.axaml +++ b/src/Artemis.UI/Screens/Home/HomeView.axaml @@ -43,7 +43,7 @@ Under Settings > Plugins you can find your currently installed plugins, these default plugins are created by Artemis developers. We're also keeping track of a list of third-party plugins on our wiki. - + @@ -75,7 +75,7 @@ GitHub - + Website @@ -110,7 +110,7 @@ + NavigateUri="https://wiki.artemis-rgb.com/en/donating?mtm_campaign=artemis&mtm_kwd=home"> Donate diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarView.axaml index 4d05f405a..384a367b1 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/MenuBar/MenuBarView.axaml @@ -8,7 +8,7 @@ mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Artemis.UI.Screens.ProfileEditor.MenuBar.MenuBarView" x:DataType="menuBar:MenuBarViewModel"> - + @@ -164,44 +164,44 @@ - + - + - + - + - + - + - + - + diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/LayerHintsDialogView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/LayerHintsDialogView.axaml index 95274a66e..9500aa143 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/LayerHintsDialogView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/Dialogs/LayerHintsDialogView.axaml @@ -25,7 +25,7 @@ + NavigateUri="https://wiki.artemis-rgb.com/guides/user/profiles/layers/adaption-hints?mtm_campaign=artemis&mtm_kwd=profile-editor"> Learn more about adaption hints diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingView.axaml index 7ef69ab69..f655b1201 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/Properties/DataBinding/DataBindingView.axaml @@ -43,7 +43,7 @@ When you enable data bindings you can no longer use keyframes or normal values for this property. Learn more diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/VisualEditorView.axaml.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/VisualEditorView.axaml.cs index 3fb88d5c5..87e7b3b2e 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/VisualEditorView.axaml.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/VisualEditorView.axaml.cs @@ -63,7 +63,12 @@ public partial class VisualEditorView : ReactiveUserControl - + - + diff --git a/src/Artemis.UI/Screens/Settings/Tabs/PluginsTabView.axaml b/src/Artemis.UI/Screens/Settings/Tabs/PluginsTabView.axaml index 0627e9f73..241d8379a 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/PluginsTabView.axaml +++ b/src/Artemis.UI/Screens/Settings/Tabs/PluginsTabView.axaml @@ -17,7 +17,7 @@ - + Get more plugins diff --git a/src/Artemis.UI/Screens/Settings/Tabs/ReleasesTabView.axaml b/src/Artemis.UI/Screens/Settings/Tabs/ReleasesTabView.axaml index c3dd00ae8..54f598d32 100644 --- a/src/Artemis.UI/Screens/Settings/Tabs/ReleasesTabView.axaml +++ b/src/Artemis.UI/Screens/Settings/Tabs/ReleasesTabView.axaml @@ -28,7 +28,7 @@ TextWrapping="Wrap" Text="{CompiledBinding Channel, StringFormat='Found no releases for the \'{0}\' channel.'}"> - Learn more about channels on the wiki diff --git a/src/Artemis.UI/Screens/Sidebar/SidebarView.axaml b/src/Artemis.UI/Screens/Sidebar/SidebarView.axaml index 1b1704472..630858120 100644 --- a/src/Artemis.UI/Screens/Sidebar/SidebarView.axaml +++ b/src/Artemis.UI/Screens/Sidebar/SidebarView.axaml @@ -47,7 +47,7 @@ ToolTip.Tip="View website" ToolTip.Placement="Top" ToolTip.VerticalOffset="-5" - NavigateUri="https://artemis-rgb.com"> + NavigateUri="https://artemis-rgb.com?mtm_campaign=artemis&mtm_kwd=sidebar"> + NavigateUri="https://wiki.artemis-rgb.com?mtm_campaign=artemis&mtm_kwd=sidebar"> + NavigateUri="https://wiki.artemis-rgb.com/en/donating?mtm_campaign=artemis&mtm_kwd=sidebar"> diff --git a/src/Artemis.UI/Screens/StartupWizard/Steps/FinishStep.axaml b/src/Artemis.UI/Screens/StartupWizard/Steps/FinishStep.axaml index 6ffc4c20b..44bc5da30 100644 --- a/src/Artemis.UI/Screens/StartupWizard/Steps/FinishStep.axaml +++ b/src/Artemis.UI/Screens/StartupWizard/Steps/FinishStep.axaml @@ -33,10 +33,10 @@ Discord - + https://wiki.artemis-rgb.com/ - + https://wiki.artemis-rgb.com/en/guides/user/introduction diff --git a/src/Artemis.UI/Screens/StartupWizard/Steps/WelcomeStep.axaml b/src/Artemis.UI/Screens/StartupWizard/Steps/WelcomeStep.axaml index 5c9df872f..d9fd7883b 100644 --- a/src/Artemis.UI/Screens/StartupWizard/Steps/WelcomeStep.axaml +++ b/src/Artemis.UI/Screens/StartupWizard/Steps/WelcomeStep.axaml @@ -16,13 +16,13 @@ - + - + diff --git a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorView.axaml b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorView.axaml index f3914a73f..ade53ea24 100644 --- a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorView.axaml +++ b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorView.axaml @@ -110,14 +110,14 @@ - diff --git a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorView.axaml.cs b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorView.axaml.cs index 833a56e20..73b747355 100644 --- a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorView.axaml.cs +++ b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorView.axaml.cs @@ -5,7 +5,6 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Controls.PanAndZoom; using Avalonia.Input; -using Avalonia.Markup.Xaml; using Avalonia.Media; using Avalonia.ReactiveUI; @@ -30,7 +29,7 @@ public partial class SurfaceEditorView : ReactiveUserControl - + - + - + - + - + - + - + @@ -173,7 +173,7 @@ Grid.Column="1" VerticalAlignment="Top" HorizontalAlignment="Right" - NavigateUri="https://wiki.artemis-rgb.com/en/guides/user/profiles/nodes"> + NavigateUri="https://wiki.artemis-rgb.com/en/guides/user/profiles/nodes?mtm_campaign=artemis&mtm_kwd=script-editor"> Learn more about visual scripts diff --git a/src/Artemis.UI/Screens/VisualScripting/Pins/PinView.cs b/src/Artemis.UI/Screens/VisualScripting/Pins/PinView.cs index 2663efc64..391941487 100644 --- a/src/Artemis.UI/Screens/VisualScripting/Pins/PinView.cs +++ b/src/Artemis.UI/Screens/VisualScripting/Pins/PinView.cs @@ -3,32 +3,30 @@ using Avalonia; using Avalonia.Controls; using Avalonia.Input; using Avalonia.ReactiveUI; -using Avalonia.Rendering; +using Avalonia.Threading; using Avalonia.VisualTree; namespace Artemis.UI.Screens.VisualScripting.Pins; public class PinView : ReactiveUserControl { - private Canvas? _container; + private readonly DispatcherTimer _updateTimer; private bool _dragging; + private Canvas? _container; private Border? _pinPoint; - private PinViewRenderLoopTaks _renderLoopTask; + + public PinView() + { + _updateTimer = new DispatcherTimer(TimeSpan.FromMilliseconds(16), DispatcherPriority.Render, UpdatePosition); + } protected void InitializePin(Border pinPoint) { _pinPoint = pinPoint; _pinPoint.PointerMoved += PinPointOnPointerMoved; _pinPoint.PointerReleased += PinPointOnPointerReleased; - _pinPoint.PropertyChanged += PinPointOnPropertyChanged; - _renderLoopTask = new PinViewRenderLoopTaks(this); } - - private void PinPointOnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) - { - Console.WriteLine(e); - } - + private void PinPointOnPointerMoved(object? sender, PointerEventArgs e) { if (ViewModel == null || _container == null || _pinPoint == null) @@ -74,19 +72,17 @@ public class PinView : ReactiveUserControl /// protected override void OnAttachedToVisualTree(VisualTreeAttachmentEventArgs e) { - base.OnAttachedToVisualTree(e); _container = this.FindAncestorOfType(); - AvaloniaLocator.Current.GetRequiredService().Add(_renderLoopTask); + _updateTimer.Start(); } /// protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) { - base.OnDetachedFromVisualTree(e); - AvaloniaLocator.Current.GetRequiredService().Remove(_renderLoopTask); + _updateTimer.Stop(); } - public void UpdatePosition() + public void UpdatePosition(object? sender, EventArgs eventArgs) { if (_container == null || _pinPoint == null || ViewModel == null) return; @@ -97,25 +93,4 @@ public class PinView : ReactiveUserControl } #endregion -} - -public class PinViewRenderLoopTaks : IRenderLoopTask -{ - private readonly PinView _pinView; - - public PinViewRenderLoopTaks(PinView pinView) - { - _pinView = pinView; - } - - public void Update(TimeSpan time) - { - _pinView.UpdatePosition(); - } - - public void Render() - { - } - - public bool NeedsUpdate => true; } \ No newline at end of file diff --git a/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj b/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj index 2a69a2d53..c0e7a1bec 100644 --- a/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj +++ b/src/Artemis.VisualScripting/Artemis.VisualScripting.csproj @@ -8,9 +8,9 @@ - - - + + + diff --git a/src/Artemis.VisualScripting/Nodes/Mathematics/MathExpressionNode.cs b/src/Artemis.VisualScripting/Nodes/Mathematics/MathExpressionNode.cs index 305373b97..21d938865 100644 --- a/src/Artemis.VisualScripting/Nodes/Mathematics/MathExpressionNode.cs +++ b/src/Artemis.VisualScripting/Nodes/Mathematics/MathExpressionNode.cs @@ -5,7 +5,7 @@ using NoStringEvaluating.Models.FormulaChecker; namespace Artemis.VisualScripting.Nodes.Mathematics; -[Node("Math Expression", "Outputs the result of a math expression.", "Mathematics", "https://wiki.artemis-rgb.com/en/guides/user/profiles/nodes/mathematics/math-expression", InputType = typeof(Numeric), OutputType = typeof(Numeric))] +[Node("Math Expression", "Outputs the result of a math expression.", "Mathematics", "https://wiki.artemis-rgb.com/en/guides/user/profiles/nodes/mathematics/math-expression?mtm_campaign=artemis&mtm_kwd=node-help", InputType = typeof(Numeric), OutputType = typeof(Numeric))] public class MathExpressionNode : Node { private readonly IFormulaChecker _checker;