From c36110e79d82b87bf0d87004a01a92a9126dbab6 Mon Sep 17 00:00:00 2001 From: Robert Date: Sun, 6 Feb 2022 00:00:48 +0100 Subject: [PATCH] Profile editor - Visualization fixes Profile editor - Timeline fixes --- src/Artemis.ConsoleUI/packages.lock.json | 179 +----------------- src/Artemis.Core/Models/Profile/Folder.cs | 6 + src/Artemis.Core/Models/Profile/Layer.cs | 6 + src/Artemis.Core/Models/Profile/Timeline.cs | 34 ++-- .../LayerBrushes/Internal/BaseLayerBrush.cs | 1 + src/Artemis.Core/Services/CoreService.cs | 1 + .../Controls/SelectionRectangle.cs | 19 +- .../Commands/ToggleLayerPropertyKeyframes.cs | 32 +++- .../Artemis.UI.Shared/Styles/Button.axaml | 17 ++ .../Performance/PerformanceDebugView.axaml | 16 +- .../Performance/PerformanceDebugViewModel.cs | 67 ++++++- .../Tabs/Render/RenderDebugView.axaml | 17 +- .../Tabs/Render/RenderDebugViewModel.cs | 1 - .../Tools/SelectionAddToolView.axaml | 4 +- .../Tools/SelectionAddToolView.axaml.cs | 3 +- .../Tools/SelectionAddToolViewModel.cs | 20 +- .../Tools/SelectionRemoveToolView.axaml | 4 +- .../LayerShapeVisualizerView.axaml | 37 ++-- .../LayerShapeVisualizerView.axaml.cs | 45 ++++- .../Visualizers/LayerVisualizerView.axaml | 8 +- .../Visualizers/LayerVisualizerView.axaml.cs | 42 +++- .../Screens/Root/DefaultTitleBarView.axaml | 2 +- 22 files changed, 331 insertions(+), 230 deletions(-) diff --git a/src/Artemis.ConsoleUI/packages.lock.json b/src/Artemis.ConsoleUI/packages.lock.json index 2c3004e65..45239c58c 100644 --- a/src/Artemis.ConsoleUI/packages.lock.json +++ b/src/Artemis.ConsoleUI/packages.lock.json @@ -74,47 +74,10 @@ "System.Xml.XmlDocument": "4.3.0" } }, - "EmbedIO": { - "type": "Transitive", - "resolved": "3.4.3", - "contentHash": "YM6hpZNAfvbbixfG9T4lWDGfF0D/TqutbTROL4ogVcHKwPF1hp+xS3ABwd3cxxTxvDFkj/zZl57QgWuFA8Igxw==", - "dependencies": { - "Unosquare.Swan.Lite": "3.0.0" - } - }, - "HidSharp": { - "type": "Transitive", - "resolved": "2.1.0", - "contentHash": "UTdxWvbgp2xzT1Ajaa2va+Qi3oNHJPasYmVhbKI2VVdu1VYP6yUG+RikhsHvpD7iM0S8e8UYb5Qm/LTWxx9QAA==" - }, - "LiteDB": { - "type": "Transitive", - "resolved": "5.0.11", - "contentHash": "6cL4bOmVCUB0gIK+6qIr68HeqjjHZicPDGQjvJ87mIOvkFsEsJWkIps3yoKNeLpHhJQur++yoQ9Q8gxsdos0xQ==" - }, - "McMaster.NETCore.Plugins": { - "type": "Transitive", - "resolved": "1.4.0", - "contentHash": "UKw5Z2/QHhkR7kiAJmqdCwVDMQV0lwsfj10+FG676r8DsJWIpxtachtEjE0qBs9WoK5GUQIqxgyFeYUSwuPszg==", - "dependencies": { - "Microsoft.DotNet.PlatformAbstractions": "3.1.6", - "Microsoft.Extensions.DependencyModel": "5.0.0" - } - }, - "Microsoft.DotNet.PlatformAbstractions": { - "type": "Transitive", - "resolved": "3.1.6", - "contentHash": "jek4XYaQ/PGUwDKKhwR8K47Uh1189PFzMeLqO83mXrXQVIpARZCcfuDedH50YDTepBkfijCZN5U/vZi++erxtg==" - }, - "Microsoft.Extensions.DependencyModel": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "umBECCoMC+sOUgm083yFr8SxTobUOcPFH4AXigdO2xJiszCHAnmeDl4qPphJt+oaJ/XIfV1wOjIts2nRnki61Q==" - }, "Microsoft.NETCore.Platforms": { "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "VyPlqzH2wavqquTcYpkIIAQ6WdenuKoFN0BdYBbCWsclXacSOHNQn66Gt4z5NBqEYW0FAPm5rlvki9ZiCij5xQ==" + "resolved": "1.1.0", + "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A==" }, "Microsoft.NETCore.Targets": { "type": "Transitive", @@ -182,19 +145,6 @@ "System.Xml.XDocument": "4.3.0" } }, - "Newtonsoft.Json": { - "type": "Transitive", - "resolved": "13.0.1", - "contentHash": "ppPFpBcvxdsfUonNcvITKqLl3bqxWbDCZIzDWHzjpdAHRFfZe0Dw9HmA0+za13IdyrgJwpkDTDA9fHaxOrt20A==" - }, - "Ninject.Extensions.ChildKernel": { - "type": "Transitive", - "resolved": "3.3.0", - "contentHash": "vl/p3f8sIaCCHiKsjhq9R8n3bH705Hu1WJXNpMEz1UC79EV51Mk5TWYXQbRnsK20hxF48CiAgUBb9pMKfX6sLw==", - "dependencies": { - "Ninject": "3.3.4" - } - }, "Ninject.Extensions.Factory": { "type": "Transitive", "resolved": "3.3.2", @@ -204,27 +154,6 @@ "Ninject": "3.3.3" } }, - "RGB.NET.Core": { - "type": "Transitive", - "resolved": "1.0.0-prerelease7", - "contentHash": "IIja5sC4QZ5pbSNckRCG7TlY4U6j/dRbrl4e2FZqsTGgsevaVB3IqonUQLFY1GGst4xNSl2oh0A23coXQxXGbQ==" - }, - "RGB.NET.Layout": { - "type": "Transitive", - "resolved": "1.0.0-prerelease7", - "contentHash": "S0kfWVa8EfMOAl2WPHsq98dwaO+SNz9TWr1AtMkdo8aZuYIVhaJ1c+mSAMMnH1V+mSbxDWPHWkNzi9ITszJucA==", - "dependencies": { - "RGB.NET.Core": "1.0.0-prerelease7" - } - }, - "RGB.NET.Presets": { - "type": "Transitive", - "resolved": "1.0.0-prerelease7", - "contentHash": "NgShvOPQM0miOsdqMKjkNunngJUZMwr8KR8ME2/Ksir7wgIQfgJj1YwZy8aIj+ar7fDo6VZJZenAshs/Ul+04A==", - "dependencies": { - "RGB.NET.Core": "1.0.0-prerelease7" - } - }, "runtime.debian.8-x64.runtime.native.System.Security.Cryptography.OpenSsl": { "type": "Transitive", "resolved": "4.3.0", @@ -332,38 +261,6 @@ "resolved": "4.3.0", "contentHash": "VB5cn/7OzUfzdnC8tqAIMQciVLiq2epm2NrAm1E9OjNRyG4lVhfR61SMcLizejzQP8R8Uf/0l5qOIbUEi+RdEg==" }, - "Serilog.Sinks.Console": { - "type": "Transitive", - "resolved": "4.0.0", - "contentHash": "yJQit9sTJ4xGLKgCujqDJsaGqBNJwGB/H898z+xYlMG06twy4//6LLnSrsmpduZxcHIG4im7cv+JmXLzXz2EkQ==", - "dependencies": { - "Serilog": "2.10.0" - } - }, - "Serilog.Sinks.Debug": { - "type": "Transitive", - "resolved": "2.0.0", - "contentHash": "Y6g3OBJ4JzTyyw16fDqtFcQ41qQAydnEvEqmXjhwhgjsnG/FaJ8GUqF5ldsC/bVkK8KYmqrPhDO+tm4dF6xx4A==", - "dependencies": { - "Serilog": "2.10.0" - } - }, - "Serilog.Sinks.File": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "uwV5hdhWPwUH1szhO8PJpFiahqXmzPzJT/sOijH/kFgUx+cyoDTMM8MHD0adw9+Iem6itoibbUXHYslzXsLEAg==", - "dependencies": { - "Serilog": "2.10.0" - } - }, - "SkiaSharp": { - "type": "Transitive", - "resolved": "2.80.3", - "contentHash": "qX6tGNP3+MXNYe2pKm0PCRiJ/cx+LTeLaggwZifB7sUMXhECfKKKHJq45VqZKt37xQegnCCdf1jHXwmHeJQs5Q==", - "dependencies": { - "System.Memory": "4.5.3" - } - }, "System.AppContext": { "type": "Transitive", "resolved": "4.3.0", @@ -656,15 +553,6 @@ "System.Threading.Tasks": "4.3.0" } }, - "System.IO.FileSystem.AccessControl": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "SxHB3nuNrpptVk+vZ/F+7OHEpoHUIKKMl02bUmYHQr1r+glbZQxs7pRtsf4ENO29TVm2TH3AEeep2fJcy92oYw==", - "dependencies": { - "System.Security.AccessControl": "5.0.0", - "System.Security.Principal.Windows": "5.0.0" - } - }, "System.IO.FileSystem.Primitives": { "type": "Transitive", "resolved": "4.3.0", @@ -709,11 +597,6 @@ "System.Threading": "4.3.0" } }, - "System.Memory": { - "type": "Transitive", - "resolved": "4.5.3", - "contentHash": "3oDzvc/zzetpTKWMShs1AADwZjQ/36HnsufHRPcOjyRAAMLDlu2iD33MBI2opxnezcVUtXyqDXXjoFMOU9c7SA==" - }, "System.Net.Http": { "type": "Transitive", "resolved": "4.3.0", @@ -839,11 +722,6 @@ "System.Runtime": "4.3.0" } }, - "System.Reflection.Metadata": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "5NecZgXktdGg34rh1OenY1rFNDCI8xSjFr+Z4OU4cU06AQHUdRnIIEeWENu3Wl4YowbzkymAIMvi3WyK9U53pQ==" - }, "System.Reflection.Primitives": { "type": "Transitive", "resolved": "4.3.0", @@ -942,15 +820,6 @@ "System.Runtime.Extensions": "4.3.0" } }, - "System.Security.AccessControl": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "dagJ1mHZO3Ani8GH0PHpPEe/oYO+rVdbQjvjJkBRNQkX4t0r1iaeGn8+/ybkSLEan3/slM0t59SVdHzuHf2jmw==", - "dependencies": { - "Microsoft.NETCore.Platforms": "5.0.0", - "System.Security.Principal.Windows": "5.0.0" - } - }, "System.Security.Cryptography.Algorithms": { "type": "Transitive", "resolved": "4.3.0", @@ -1095,11 +964,6 @@ "runtime.native.System.Security.Cryptography.OpenSsl": "4.3.0" } }, - "System.Security.Principal.Windows": { - "type": "Transitive", - "resolved": "5.0.0", - "contentHash": "t0MGLukB5WAVU9bO3MGzvlGnyJPgUlcwerXn1kzBRjwLKixT96XV0Uza41W49gVd8zEMFu9vQEFlv0IOrytICA==" - }, "System.Text.Encoding": { "type": "Transitive", "resolved": "4.3.0", @@ -1226,45 +1090,8 @@ "System.Xml.ReaderWriter": "4.3.0" } }, - "Unosquare.Swan.Lite": { - "type": "Transitive", - "resolved": "3.0.0", - "contentHash": "noPwJJl1Q9uparXy1ogtkmyAPGNfSGb0BLT1292nFH1jdMKje6o2kvvrQUvF9Xklj+IoiAI0UzF6Aqxlvo10lw==" - }, "artemis.core": { - "type": "Project", - "dependencies": { - "Artemis.Storage": "1.0.0", - "EmbedIO": "3.4.3", - "HidSharp": "2.1.0", - "Humanizer.Core": "2.11.10", - "LiteDB": "5.0.11", - "McMaster.NETCore.Plugins": "1.4.0", - "Newtonsoft.Json": "13.0.1", - "Ninject": "3.3.4", - "Ninject.Extensions.ChildKernel": "3.3.0", - "Ninject.Extensions.Conventions": "3.3.0", - "RGB.NET.Core": "1.0.0-prerelease7", - "RGB.NET.Layout": "1.0.0-prerelease7", - "RGB.NET.Presets": "1.0.0-prerelease7", - "Serilog": "2.10.0", - "Serilog.Sinks.Console": "4.0.0", - "Serilog.Sinks.Debug": "2.0.0", - "Serilog.Sinks.File": "5.0.0", - "SkiaSharp": "2.80.3", - "System.Buffers": "4.5.1", - "System.IO.FileSystem.AccessControl": "5.0.0", - "System.Numerics.Vectors": "4.5.0", - "System.Reflection.Metadata": "5.0.0", - "System.ValueTuple": "4.5.0" - } - }, - "artemis.storage": { - "type": "Project", - "dependencies": { - "LiteDB": "5.0.11", - "Serilog": "2.10.0" - } + "type": "Project" } } } diff --git a/src/Artemis.Core/Models/Profile/Folder.cs b/src/Artemis.Core/Models/Profile/Folder.cs index dd00ed756..e77a5a6ad 100644 --- a/src/Artemis.Core/Models/Profile/Folder.cs +++ b/src/Artemis.Core/Models/Profile/Folder.cs @@ -94,6 +94,12 @@ namespace Artemis.Core if (Disposed) throw new ObjectDisposedException("Folder"); + if (Timeline.IsOverridden) + { + Timeline.ClearOverride(); + return; + } + UpdateDisplayCondition(); UpdateTimeline(deltaTime); diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs index 3512496f3..11a34940c 100644 --- a/src/Artemis.Core/Models/Profile/Layer.cs +++ b/src/Artemis.Core/Models/Profile/Layer.cs @@ -338,6 +338,12 @@ namespace Artemis.Core if (Disposed) throw new ObjectDisposedException("Layer"); + if (Timeline.IsOverridden) + { + Timeline.ClearOverride(); + return; + } + UpdateDisplayCondition(); UpdateTimeline(deltaTime); diff --git a/src/Artemis.Core/Models/Profile/Timeline.cs b/src/Artemis.Core/Models/Profile/Timeline.cs index 4e17d746f..606f0ba8b 100644 --- a/src/Artemis.Core/Models/Profile/Timeline.cs +++ b/src/Artemis.Core/Models/Profile/Timeline.cs @@ -20,7 +20,7 @@ public class Timeline : CorePropertyChanged, IStorageModel { Entity = new TimelineEntity(); MainSegmentLength = TimeSpan.FromSeconds(5); - + Save(); } @@ -36,7 +36,7 @@ public class Timeline : CorePropertyChanged, IStorageModel { return $"Progress: {Position}/{Length} - delta: {Delta}"; } - + #region Properties private TimeSpan _position; @@ -46,7 +46,8 @@ public class Timeline : CorePropertyChanged, IStorageModel private TimeSpan _startSegmentLength; private TimeSpan _mainSegmentLength; private TimeSpan _endSegmentLength; - + private TimeSpan _lastOverride; + /// /// Gets the current position of the timeline /// @@ -65,7 +66,7 @@ public class Timeline : CorePropertyChanged, IStorageModel get => _lastDelta; private set => SetAndNotify(ref _lastDelta, value); } - + /// /// Gets or sets the mode in which the render element starts its timeline when display conditions are met /// @@ -251,8 +252,6 @@ public class Timeline : CorePropertyChanged, IStorageModel #region Updating - private TimeSpan _lastOverridePosition; - /// /// Updates the timeline, applying the provided to the /// @@ -262,12 +261,12 @@ public class Timeline : CorePropertyChanged, IStorageModel { lock (_lock) { + if (IsOverridden) + throw new ArtemisCoreException("Can't update an overridden timeline, call ClearOverride first."); + Delta += delta; Position += delta; - IsOverridden = false; - _lastOverridePosition = Position; - if (!stickToMainSegment || Position <= MainSegmentEndPosition) return; @@ -334,16 +333,19 @@ public class Timeline : CorePropertyChanged, IStorageModel { lock (_lock) { - Delta += position - _lastOverridePosition; - Position = position; + if (_lastOverride == TimeSpan.Zero) + Delta = Position - position; + else + Delta = position - _lastOverride; + Position = position; IsOverridden = true; - _lastOverridePosition = position; + _lastOverride = position; if (!stickToMainSegment || Position < MainSegmentStartPosition) return; - bool atSegmentStart = Position == MainSegmentStartPosition; + bool atSegmentStart = Position >= MainSegmentStartPosition; if (MainSegmentLength > TimeSpan.Zero) { Position = MainSegmentStartPosition + TimeSpan.FromMilliseconds(Position.TotalMilliseconds % MainSegmentLength.TotalMilliseconds); @@ -359,6 +361,12 @@ public class Timeline : CorePropertyChanged, IStorageModel } } + internal void ClearOverride() + { + IsOverridden = false; + _lastOverride = TimeSpan.Zero; + } + /// /// Sets the to /// diff --git a/src/Artemis.Core/Plugins/LayerBrushes/Internal/BaseLayerBrush.cs b/src/Artemis.Core/Plugins/LayerBrushes/Internal/BaseLayerBrush.cs index 69027def6..24d54ae82 100644 --- a/src/Artemis.Core/Plugins/LayerBrushes/Internal/BaseLayerBrush.cs +++ b/src/Artemis.Core/Plugins/LayerBrushes/Internal/BaseLayerBrush.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Diagnostics; using System.Linq; using Artemis.Storage.Entities.Profile; using SkiaSharp; diff --git a/src/Artemis.Core/Services/CoreService.cs b/src/Artemis.Core/Services/CoreService.cs index f8b0ffbcd..15a9a71a5 100644 --- a/src/Artemis.Core/Services/CoreService.cs +++ b/src/Artemis.Core/Services/CoreService.cs @@ -218,6 +218,7 @@ namespace Artemis.Core.Services ); _logger.Information("Startup arguments: {args}", StartupArguments); _logger.Information("Elevated permissions: {perms}", IsElevated); + _logger.Information("Stopwatch high resolution: {perms}", Stopwatch.IsHighResolution); ApplyLoggingLevel(); diff --git a/src/Avalonia/Artemis.UI.Shared/Controls/SelectionRectangle.cs b/src/Avalonia/Artemis.UI.Shared/Controls/SelectionRectangle.cs index 3866dcfb1..c51659c1b 100644 --- a/src/Avalonia/Artemis.UI.Shared/Controls/SelectionRectangle.cs +++ b/src/Avalonia/Artemis.UI.Shared/Controls/SelectionRectangle.cs @@ -43,6 +43,13 @@ public class SelectionRectangle : Control public static readonly StyledProperty InputElementProperty = AvaloniaProperty.Register(nameof(InputElement), notifying: OnInputElementChanged); + /// + /// Defines the property. + /// + public static readonly StyledProperty ZoomRatioProperty = + AvaloniaProperty.Register(nameof(ZoomRatio), 1); + + /// /// Defines the read-only property. /// @@ -108,6 +115,15 @@ public class SelectionRectangle : Control set => SetValue(InputElementProperty, value); } + /// + /// Gets or sets the zoom ratio to counteract when drawing + /// + public double ZoomRatio + { + get => GetValue(ZoomRatioProperty); + set => SetValue(ZoomRatioProperty, value); + } + /// /// Gets a boolean indicating whether the selection rectangle is currently performing a selection. /// @@ -149,6 +165,7 @@ public class SelectionRectangle : Control { ((SelectionRectangle) sender).SubscribeToInputElement(); } + private void ParentOnPointerPressed(object? sender, PointerPressedEventArgs e) { @@ -227,7 +244,7 @@ public class SelectionRectangle : Control public override void Render(DrawingContext drawingContext) { if (_displayRect != null) - drawingContext.DrawRectangle(Background, new Pen(BorderBrush, BorderThickness), _displayRect.Value, BorderRadius, BorderRadius); + drawingContext.DrawRectangle(Background, new Pen(BorderBrush, BorderThickness / ZoomRatio), _displayRect.Value, BorderRadius / ZoomRatio, BorderRadius / ZoomRatio); } /// diff --git a/src/Avalonia/Artemis.UI.Shared/Services/ProfileEditor/Commands/ToggleLayerPropertyKeyframes.cs b/src/Avalonia/Artemis.UI.Shared/Services/ProfileEditor/Commands/ToggleLayerPropertyKeyframes.cs index d5c77b3ac..cea583b33 100644 --- a/src/Avalonia/Artemis.UI.Shared/Services/ProfileEditor/Commands/ToggleLayerPropertyKeyframes.cs +++ b/src/Avalonia/Artemis.UI.Shared/Services/ProfileEditor/Commands/ToggleLayerPropertyKeyframes.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using Artemis.Core; namespace Artemis.UI.Shared.Services.ProfileEditor.Commands; @@ -32,16 +33,37 @@ public class ToggleLayerPropertyKeyframes : IProfileEditorCommand /// public void Execute() { - _keyframe ??= new LayerPropertyKeyframe(_layerProperty.CurrentValue, _time, Easings.Functions.Linear, _layerProperty); - _layerProperty.KeyframesEnabled = _enable; - _layerProperty.AddKeyframe(_keyframe); + if (_enable) + { + _layerProperty.KeyframesEnabled = true; + + // If there weren't any keyframes yet, add one with the current value at the current time + if (!_layerProperty.Keyframes.Any()) + { + // If executed before, reuse the previous keyframe + _keyframe ??= new LayerPropertyKeyframe(_layerProperty.CurrentValue, _time, Easings.Functions.Linear, _layerProperty); + _layerProperty.AddKeyframe(_keyframe); + } + } + else + { + _layerProperty.KeyframesEnabled = false; + } } /// public void Undo() { - _layerProperty.RemoveKeyframe(_keyframe!); - _layerProperty.KeyframesEnabled = !_enable; + if (_enable) + { + if (_keyframe != null) + _layerProperty.RemoveKeyframe(_keyframe); + _layerProperty.KeyframesEnabled = false; + } + else + { + _layerProperty.KeyframesEnabled = true; + } } #endregion diff --git a/src/Avalonia/Artemis.UI.Shared/Styles/Button.axaml b/src/Avalonia/Artemis.UI.Shared/Styles/Button.axaml index 8c3eadb1b..adb50e2b4 100644 --- a/src/Avalonia/Artemis.UI.Shared/Styles/Button.axaml +++ b/src/Avalonia/Artemis.UI.Shared/Styles/Button.axaml @@ -33,6 +33,12 @@ + + + Button.window-button + @@ -69,4 +75,15 @@ + + + \ No newline at end of file diff --git a/src/Avalonia/Artemis.UI/Screens/Debugger/Tabs/Performance/PerformanceDebugView.axaml b/src/Avalonia/Artemis.UI/Screens/Debugger/Tabs/Performance/PerformanceDebugView.axaml index ccd646ccf..adb0fd87f 100644 --- a/src/Avalonia/Artemis.UI/Screens/Debugger/Tabs/Performance/PerformanceDebugView.axaml +++ b/src/Avalonia/Artemis.UI/Screens/Debugger/Tabs/Performance/PerformanceDebugView.axaml @@ -5,7 +5,7 @@ xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Artemis.UI.Screens.Debugger.Performance.PerformanceDebugView"> - + Performance @@ -21,7 +21,19 @@ - + + + + + + + + + + + + + diff --git a/src/Avalonia/Artemis.UI/Screens/Debugger/Tabs/Performance/PerformanceDebugViewModel.cs b/src/Avalonia/Artemis.UI/Screens/Debugger/Tabs/Performance/PerformanceDebugViewModel.cs index 781ff7e3c..1afef3043 100644 --- a/src/Avalonia/Artemis.UI/Screens/Debugger/Tabs/Performance/PerformanceDebugViewModel.cs +++ b/src/Avalonia/Artemis.UI/Screens/Debugger/Tabs/Performance/PerformanceDebugViewModel.cs @@ -8,16 +8,23 @@ using Artemis.Core; using Artemis.Core.Services; using Artemis.UI.Shared; using ReactiveUI; +using SkiaSharp; namespace Artemis.UI.Screens.Debugger.Performance { public class PerformanceDebugViewModel : ActivatableViewModelBase, IRoutableViewModel { + private readonly ICoreService _coreService; private readonly IPluginManagementService _pluginManagementService; + private double _currentFps; + private string? _renderer; + private int _renderHeight; + private int _renderWidth; - public PerformanceDebugViewModel(IScreen hostScreen, IPluginManagementService pluginManagementService) + public PerformanceDebugViewModel(IScreen hostScreen, ICoreService coreService, IPluginManagementService pluginManagementService) { HostScreen = hostScreen; + _coreService = coreService; _pluginManagementService = pluginManagementService; Timer updateTimer = new(500); @@ -38,6 +45,7 @@ namespace Artemis.UI.Screens.Debugger.Performance .Subscribe(_ => Repopulate()) .DisposeWith(disposables); + HandleActivation(); PopulateItems(); updateTimer.Start(); @@ -45,21 +53,57 @@ namespace Artemis.UI.Screens.Debugger.Performance { updateTimer.Stop(); Items.Clear(); + HandleDeactivation(); }).DisposeWith(disposables); }); } - public ObservableCollection Items { get; } = new(); - + public string UrlPathSegment => "performance"; public IScreen HostScreen { get; } + public ObservableCollection Items { get; } = new(); + + public double CurrentFps + { + get => _currentFps; + set => this.RaiseAndSetIfChanged(ref _currentFps, value); + } + + public int RenderWidth + { + get => _renderWidth; + set => this.RaiseAndSetIfChanged(ref _renderWidth, value); + } + + public int RenderHeight + { + get => _renderHeight; + set => this.RaiseAndSetIfChanged(ref _renderHeight, value); + } + + public string? Renderer + { + get => _renderer; + set => this.RaiseAndSetIfChanged(ref _renderer, value); + } + + private void HandleActivation() + { + Renderer = Constants.ManagedGraphicsContext != null ? Constants.ManagedGraphicsContext.GetType().Name : "Software"; + _coreService.FrameRendered += CoreServiceOnFrameRendered; + } + + private void HandleDeactivation() + { + _coreService.FrameRendered -= CoreServiceOnFrameRendered; + } private void PopulateItems() { foreach (PerformanceDebugPluginViewModel performanceDebugPluginViewModel in _pluginManagementService.GetAllPlugins() - .Where(p => p.IsEnabled && p.Profilers.Any(pr => pr.Measurements.Any())) - .OrderBy(p => p.Info.Name) - .Select(p => new PerformanceDebugPluginViewModel(p))) + .Where(p => p.IsEnabled && p.Profilers.Any(pr => pr.Measurements.Any())) + .OrderBy(p => p.Info.Name) + .Select(p => new PerformanceDebugPluginViewModel(p))) Items.Add(performanceDebugPluginViewModel); } @@ -69,10 +113,19 @@ namespace Artemis.UI.Screens.Debugger.Performance PopulateItems(); } - private void UpdateTimerOnElapsed(object sender, ElapsedEventArgs e) + private void UpdateTimerOnElapsed(object? sender, ElapsedEventArgs e) { foreach (PerformanceDebugPluginViewModel viewModel in Items) viewModel.Update(); } + + private void CoreServiceOnFrameRendered(object? sender, FrameRenderedEventArgs e) + { + CurrentFps = _coreService.FrameRate; + SKImageInfo bitmapInfo = e.Texture.ImageInfo; + + RenderHeight = bitmapInfo.Height; + RenderWidth = bitmapInfo.Width; + } } } \ No newline at end of file diff --git a/src/Avalonia/Artemis.UI/Screens/Debugger/Tabs/Render/RenderDebugView.axaml b/src/Avalonia/Artemis.UI/Screens/Debugger/Tabs/Render/RenderDebugView.axaml index 3143eeecf..e29e77355 100644 --- a/src/Avalonia/Artemis.UI/Screens/Debugger/Tabs/Render/RenderDebugView.axaml +++ b/src/Avalonia/Artemis.UI/Screens/Debugger/Tabs/Render/RenderDebugView.axaml @@ -24,6 +24,21 @@ - + + + + + + + + + + + \ No newline at end of file diff --git a/src/Avalonia/Artemis.UI/Screens/Debugger/Tabs/Render/RenderDebugViewModel.cs b/src/Avalonia/Artemis.UI/Screens/Debugger/Tabs/Render/RenderDebugViewModel.cs index 6729680c5..51d1bf5a7 100644 --- a/src/Avalonia/Artemis.UI/Screens/Debugger/Tabs/Render/RenderDebugViewModel.cs +++ b/src/Avalonia/Artemis.UI/Screens/Debugger/Tabs/Render/RenderDebugViewModel.cs @@ -102,7 +102,6 @@ namespace Artemis.UI.Screens.Debugger.Render } } - public string UrlPathSegment => "render"; public IScreen HostScreen { get; } } diff --git a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Tools/SelectionAddToolView.axaml b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Tools/SelectionAddToolView.axaml index 2e3c5aaae..f6246fcce 100644 --- a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Tools/SelectionAddToolView.axaml +++ b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Tools/SelectionAddToolView.axaml @@ -9,7 +9,9 @@ + BorderThickness="2" + SelectionFinished="SelectionRectangle_OnSelectionFinished" + ZoomRatio="{Binding $parent[ZoomBorder].ZoomX}"> diff --git a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Tools/SelectionAddToolView.axaml.cs b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Tools/SelectionAddToolView.axaml.cs index 0110136ed..b8938f4f5 100644 --- a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Tools/SelectionAddToolView.axaml.cs +++ b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Tools/SelectionAddToolView.axaml.cs @@ -1,4 +1,5 @@ using Artemis.UI.Shared.Events; +using Avalonia.Input; using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; using Avalonia.Skia; @@ -19,6 +20,6 @@ public class SelectionAddToolView : ReactiveUserControl leds = _rgbService.EnabledDevices.SelectMany(d => d.Leds).Where(l => l.AbsoluteRectangle.IntersectsWith(rect)).ToList(); - _profileEditorService.ExecuteCommand(new ChangeLayerLeds(_layer, leds)); + if (inverse) + { + List toRemove = _layer.Leds.Where(l => l.AbsoluteRectangle.IntersectsWith(rect)).ToList(); + List toAdd = _rgbService.EnabledDevices.SelectMany(d => d.Leds).Where(l => l.AbsoluteRectangle.IntersectsWith(rect)).Except(toRemove).ToList(); + List leds = _layer.Leds.Except(toRemove).ToList(); + leds.AddRange(toAdd); + + _profileEditorService.ExecuteCommand(new ChangeLayerLeds(_layer, leds)); + } + else + { + List leds = _rgbService.EnabledDevices.SelectMany(d => d.Leds).Where(l => l.AbsoluteRectangle.IntersectsWith(rect)).ToList(); + if (expand) + leds.AddRange(_layer.Leds); + _profileEditorService.ExecuteCommand(new ChangeLayerLeds(_layer, leds.Distinct().ToList())); + } } } \ No newline at end of file diff --git a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Tools/SelectionRemoveToolView.axaml b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Tools/SelectionRemoveToolView.axaml index 0823320a9..69dbdc20e 100644 --- a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Tools/SelectionRemoveToolView.axaml +++ b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Tools/SelectionRemoveToolView.axaml @@ -11,7 +11,9 @@ + BorderThickness="2" + SelectionFinished="SelectionRectangle_OnSelectionFinished" + ZoomRatio="{Binding $parent[ZoomBorder].ZoomX}"> diff --git a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Visualizers/LayerShapeVisualizerView.axaml b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Visualizers/LayerShapeVisualizerView.axaml index 4ea1dd32d..703ec1b30 100644 --- a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Visualizers/LayerShapeVisualizerView.axaml +++ b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Visualizers/LayerShapeVisualizerView.axaml @@ -10,38 +10,53 @@ - - - + - + \ No newline at end of file diff --git a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Visualizers/LayerShapeVisualizerView.axaml.cs b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Visualizers/LayerShapeVisualizerView.axaml.cs index cbef48437..c2e8936c0 100644 --- a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Visualizers/LayerShapeVisualizerView.axaml.cs +++ b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Visualizers/LayerShapeVisualizerView.axaml.cs @@ -1,3 +1,10 @@ +using System; +using System.Linq; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.PanAndZoom; +using Avalonia.Controls.Shapes; +using Avalonia.LogicalTree; using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; @@ -5,14 +12,50 @@ namespace Artemis.UI.Screens.ProfileEditor.VisualEditor.Visualizers { public partial class LayerShapeVisualizerView : ReactiveUserControl { + private ZoomBorder? _zoomBorder; + private readonly Path _layerVisualizerUnbound; + private readonly Path _layerVisualizer; + public LayerShapeVisualizerView() { InitializeComponent(); + _layerVisualizer = this.Get("LayerVisualizer"); + _layerVisualizerUnbound = this.Get("LayerVisualizerUnbound"); } private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } + + #region Overrides of TemplatedControl + + /// + protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) + { + _zoomBorder = (ZoomBorder?) this.GetLogicalAncestors().FirstOrDefault(l => l is ZoomBorder); + if (_zoomBorder != null) + _zoomBorder.PropertyChanged += ZoomBorderOnPropertyChanged; + base.OnAttachedToLogicalTree(e); + } + + /// + protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e) + { + if (_zoomBorder != null) + _zoomBorder.PropertyChanged -= ZoomBorderOnPropertyChanged; + base.OnDetachedFromLogicalTree(e); + } + + private void ZoomBorderOnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) + { + if (e.Property != ZoomBorder.ZoomXProperty || _zoomBorder == null) + return; + + _layerVisualizer.StrokeThickness = Math.Max(1, 4 / _zoomBorder.ZoomX); + _layerVisualizerUnbound.StrokeThickness = _layerVisualizer.StrokeThickness; + } + + #endregion } -} +} \ No newline at end of file diff --git a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Visualizers/LayerVisualizerView.axaml b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Visualizers/LayerVisualizerView.axaml index 1ba74c263..b5cc6011c 100644 --- a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Visualizers/LayerVisualizerView.axaml +++ b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Visualizers/LayerVisualizerView.axaml @@ -15,14 +15,14 @@ - - + \ No newline at end of file diff --git a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Visualizers/LayerVisualizerView.axaml.cs b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Visualizers/LayerVisualizerView.axaml.cs index ba1264dea..bb00950f2 100644 --- a/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Visualizers/LayerVisualizerView.axaml.cs +++ b/src/Avalonia/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/Visualizers/LayerVisualizerView.axaml.cs @@ -1,18 +1,58 @@ +using System; +using System.Linq; +using Avalonia; +using Avalonia.Controls; +using Avalonia.Controls.PanAndZoom; +using Avalonia.Controls.Shapes; +using Avalonia.LogicalTree; using Avalonia.Markup.Xaml; using Avalonia.ReactiveUI; +using Avalonia.VisualTree; namespace Artemis.UI.Screens.ProfileEditor.VisualEditor.Visualizers { public partial class LayerVisualizerView : ReactiveUserControl { + private ZoomBorder? _zoomBorder; + private readonly Path _layerVisualizer; + public LayerVisualizerView() { InitializeComponent(); + _layerVisualizer = this.Get("LayerVisualizer"); } + #region Overrides of TemplatedControl + + /// + protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e) + { + _zoomBorder = (ZoomBorder?) this.GetLogicalAncestors().FirstOrDefault(l => l is ZoomBorder); + if (_zoomBorder != null) + _zoomBorder.PropertyChanged += ZoomBorderOnPropertyChanged; + base.OnAttachedToLogicalTree(e); + } + + /// + protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e) + { + if (_zoomBorder != null) + _zoomBorder.PropertyChanged -= ZoomBorderOnPropertyChanged; + base.OnDetachedFromLogicalTree(e); + } + + private void ZoomBorderOnPropertyChanged(object? sender, AvaloniaPropertyChangedEventArgs e) + { + if (e.Property != ZoomBorder.ZoomXProperty || _zoomBorder == null) + return; + _layerVisualizer.StrokeThickness = Math.Max(1, 4 / _zoomBorder.ZoomX); + } + + #endregion + private void InitializeComponent() { AvaloniaXamlLoader.Load(this); } } -} +} \ No newline at end of file diff --git a/src/Avalonia/Artemis.UI/Screens/Root/DefaultTitleBarView.axaml b/src/Avalonia/Artemis.UI/Screens/Root/DefaultTitleBarView.axaml index 3ff09a332..3c98dac8b 100644 --- a/src/Avalonia/Artemis.UI/Screens/Root/DefaultTitleBarView.axaml +++ b/src/Avalonia/Artemis.UI/Screens/Root/DefaultTitleBarView.axaml @@ -5,7 +5,7 @@ xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" x:Class="Artemis.UI.Screens.Root.DefaultTitleBarView"> - \ No newline at end of file