mirror of
https://github.com/Artemis-RGB/Artemis
synced 2026-11-12 11:56:30 +00:00
Meta - Replace WPF projects with Avalonia projects
This commit is contained in:
1 parent
fcf0376a9a
commit
d7f3ee1190
1110 files changed
+10872
-52240
No files matched your search
@@ -0,0 +1,75 @@
|
||||
<controls:CoreWindow xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
|
||||
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
|
||||
xmlns:reactiveUi="http://reactiveui.net"
|
||||
mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="800"
|
||||
x:Class="Artemis.UI.Screens.Debugger.DebugView"
|
||||
Icon="/Assets/Images/Logo/application.ico"
|
||||
Title="Artemis | Debugger"
|
||||
Width="1200"
|
||||
Height="800">
|
||||
|
||||
<Window.Styles>
|
||||
<Style Selector="StackPanel.sidebar-stackpanel avalonia|MaterialIcon">
|
||||
<Setter Property="Margin" Value="-7 0 0 0" />
|
||||
</Style>
|
||||
<Style Selector="StackPanel.sidebar-stackpanel TextBlock">
|
||||
<Setter Property="Margin" Value="15 0 0 0" />
|
||||
</Style>
|
||||
</Window.Styles>
|
||||
|
||||
<Panel>
|
||||
<controls:NavigationView x:Name="Navigation"
|
||||
SelectedItem="{Binding SelectedItem}"
|
||||
IsPaneToggleButtonVisible="False"
|
||||
PaneDisplayMode="Left"
|
||||
Margin="0 10 0 0">
|
||||
<controls:NavigationView.MenuItems>
|
||||
<controls:NavigationViewItem Tag="Rendering">
|
||||
<controls:NavigationViewItem.Content>
|
||||
<StackPanel Orientation="Horizontal" Classes="sidebar-stackpanel">
|
||||
<avalonia:MaterialIcon Kind="Paint" />
|
||||
<TextBlock>Rendering</TextBlock>
|
||||
</StackPanel>
|
||||
</controls:NavigationViewItem.Content>
|
||||
</controls:NavigationViewItem>
|
||||
<controls:NavigationViewItem Tag="DataModel">
|
||||
<controls:NavigationViewItem.Content>
|
||||
<StackPanel Orientation="Horizontal" Classes="sidebar-stackpanel">
|
||||
<avalonia:MaterialIcon Kind="FormatListBulletedType" />
|
||||
<TextBlock>Data Model</TextBlock>
|
||||
</StackPanel>
|
||||
</controls:NavigationViewItem.Content>
|
||||
</controls:NavigationViewItem>
|
||||
<controls:NavigationViewItem Tag="Performance">
|
||||
<controls:NavigationViewItem.Content>
|
||||
<StackPanel Orientation="Horizontal" Classes="sidebar-stackpanel">
|
||||
<avalonia:MaterialIcon Kind="Gauge" />
|
||||
<TextBlock>Performance</TextBlock>
|
||||
</StackPanel>
|
||||
</controls:NavigationViewItem.Content>
|
||||
</controls:NavigationViewItem>
|
||||
<controls:NavigationViewItem Tag="Logging">
|
||||
<controls:NavigationViewItem.Content>
|
||||
<StackPanel Orientation="Horizontal" Classes="sidebar-stackpanel">
|
||||
<avalonia:MaterialIcon Kind="Text" />
|
||||
<TextBlock>Logging</TextBlock>
|
||||
</StackPanel>
|
||||
</controls:NavigationViewItem.Content>
|
||||
</controls:NavigationViewItem>
|
||||
</controls:NavigationView.MenuItems>
|
||||
|
||||
<reactiveUi:RoutedViewHost Router="{Binding Router}" Padding="12">
|
||||
<reactiveUi:RoutedViewHost.PageTransition>
|
||||
<CrossFade Duration="0.1" />
|
||||
</reactiveUi:RoutedViewHost.PageTransition>
|
||||
</reactiveUi:RoutedViewHost>
|
||||
|
||||
</controls:NavigationView>
|
||||
<StackPanel Classes="notification-container" Name="NotificationContainer" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
|
||||
</Panel>
|
||||
|
||||
</controls:CoreWindow>
|
||||
@@ -0,0 +1,47 @@
|
||||
using System;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using Artemis.UI.Shared.Events;
|
||||
using Avalonia;
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
using FluentAvalonia.Core;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Debugger
|
||||
{
|
||||
public class DebugView : ReactiveCoreWindow<DebugViewModel>
|
||||
{
|
||||
public DebugView()
|
||||
{
|
||||
InitializeComponent();
|
||||
#if DEBUG
|
||||
this.AttachDevTools();
|
||||
#endif
|
||||
|
||||
NavigationView navigation = this.Get<NavigationView>("Navigation");
|
||||
|
||||
this.WhenActivated(d =>
|
||||
{
|
||||
Observable.FromEventPattern(x => ViewModel!.ActivationRequested += x, x => ViewModel!.ActivationRequested -= x).Subscribe(_ =>
|
||||
{
|
||||
WindowState = WindowState.Normal;
|
||||
Activate();
|
||||
|
||||
}).DisposeWith(d);
|
||||
ViewModel!.SelectedItem = (NavigationViewItem) navigation.MenuItems.ElementAt(0);
|
||||
});
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
|
||||
private void DeviceVisualizer_OnLedClicked(object? sender, LedClickedEventArgs e)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Reactive.Disposables;
|
||||
using Artemis.UI.Screens.Debugger.DataModel;
|
||||
using Artemis.UI.Screens.Debugger.Logs;
|
||||
using Artemis.UI.Screens.Debugger.Performance;
|
||||
using Artemis.UI.Screens.Debugger.Render;
|
||||
using Artemis.UI.Screens.Debugger.Settings;
|
||||
using Artemis.UI.Services.Interfaces;
|
||||
using Artemis.UI.Shared;
|
||||
using FluentAvalonia.UI.Controls;
|
||||
using Ninject;
|
||||
using Ninject.Parameters;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Debugger
|
||||
{
|
||||
public class DebugViewModel : ActivatableViewModelBase, IScreen
|
||||
{
|
||||
private readonly IKernel _kernel;
|
||||
private readonly IDebugService _debugService;
|
||||
private NavigationViewItem? _selectedItem;
|
||||
|
||||
public DebugViewModel(IKernel kernel, IDebugService debugService)
|
||||
{
|
||||
_kernel = kernel;
|
||||
_debugService = debugService;
|
||||
|
||||
this.WhenAnyValue(x => x.SelectedItem).WhereNotNull().Subscribe(NavigateToSelectedItem);
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
Disposable
|
||||
.Create(HandleDeactivation)
|
||||
.DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
public NavigationViewItem? SelectedItem
|
||||
{
|
||||
get => _selectedItem;
|
||||
set => RaiseAndSetIfChanged(ref _selectedItem, value);
|
||||
}
|
||||
|
||||
private void NavigateToSelectedItem(NavigationViewItem item)
|
||||
{
|
||||
// Kind of a lame way to do this but it's so static idc
|
||||
ConstructorArgument hostScreen = new("hostScreen", this);
|
||||
switch (item.Tag as string)
|
||||
{
|
||||
case "Rendering":
|
||||
Router.Navigate.Execute(_kernel.Get<RenderDebugViewModel>(hostScreen));
|
||||
break;
|
||||
case "DataModel":
|
||||
Router.Navigate.Execute(_kernel.Get<DataModelDebugViewModel>(hostScreen));
|
||||
break;
|
||||
case "Performance":
|
||||
Router.Navigate.Execute(_kernel.Get<PerformanceDebugViewModel>(hostScreen));
|
||||
break;
|
||||
case "Logging":
|
||||
Router.Navigate.Execute(_kernel.Get<LogsDebugViewModel>(hostScreen));
|
||||
break;
|
||||
case "Settings":
|
||||
Router.Navigate.Execute(_kernel.Get<DebugSettingsViewModel>(hostScreen));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleDeactivation()
|
||||
{
|
||||
_debugService.ClearDebugger();
|
||||
}
|
||||
|
||||
public RoutingState Router { get; } = new();
|
||||
|
||||
public void Activate()
|
||||
{
|
||||
OnActivationRequested();
|
||||
}
|
||||
|
||||
public event EventHandler? ActivationRequested;
|
||||
|
||||
protected virtual void OnActivationRequested()
|
||||
{
|
||||
ActivationRequested?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:dataModel="clr-namespace:Artemis.UI.Shared.DataModelVisualization.Shared;assembly=Artemis.UI.Shared"
|
||||
xmlns:converters="clr-namespace:Artemis.UI.Shared.Converters;assembly=Artemis.UI.Shared"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.UI.Screens.Debugger.DataModel.DataModelDebugView">
|
||||
<UserControl.Resources>
|
||||
<converters:TypeToStringConverter x:Key="TypeToStringConverter" />
|
||||
</UserControl.Resources>
|
||||
<Grid RowDefinitions="Auto,*">
|
||||
<StackPanel Grid.Row="0">
|
||||
<TextBlock Classes="h3">Data Model</TextBlock>
|
||||
<TextBlock TextWrapping="Wrap">
|
||||
On this page you can view the contents of the Artemis data model.
|
||||
</TextBlock>
|
||||
<TextBlock TextWrapping="Wrap" Classes="subtitle" Margin="0 10">
|
||||
Please note that having this window open can have a performance impact on your system.
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<TreeView Grid.Row="1" Items="{Binding MainDataModel.Children}">
|
||||
<TreeView.Styles>
|
||||
<Style Selector="TreeViewItem">
|
||||
<Setter Property="IsExpanded" Value="{Binding IsVisualizationExpanded, Mode=TwoWay}" />
|
||||
</Style>
|
||||
</TreeView.Styles>
|
||||
<TreeView.DataTemplates>
|
||||
<TreeDataTemplate DataType="{x:Type dataModel:DataModelPropertiesViewModel}" ItemsSource="{Binding Children}">
|
||||
<Grid ColumnDefinitions="Auto,Auto,*">
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0 0 5 0">
|
||||
<TextBlock FontWeight="Bold">[</TextBlock>
|
||||
<TextBlock FontWeight="Bold" Text="{Binding DisplayValueType, Converter={StaticResource TypeToStringConverter}, Mode=OneWay}" />
|
||||
<TextBlock FontWeight="Bold">]</TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<TextBlock Grid.Column="1" Text="{Binding PropertyDescription.Name}" ToolTip.Tip="{Binding PropertyDescription.Description}" />
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="{Binding DisplayValue}"
|
||||
FontFamily="Consolas"
|
||||
HorizontalAlignment="Right" />
|
||||
</Grid>
|
||||
|
||||
</TreeDataTemplate>
|
||||
<TreeDataTemplate DataType="{x:Type dataModel:DataModelListViewModel}" ItemsSource="{Binding ListChildren}">
|
||||
<Grid ColumnDefinitions="Auto,Auto,*">
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0 0 5 0">
|
||||
<TextBlock FontWeight="Bold">[</TextBlock>
|
||||
<TextBlock FontWeight="Bold" Text="{Binding DisplayValueType, Converter={StaticResource TypeToStringConverter}, Mode=OneWay}" />
|
||||
<TextBlock FontWeight="Bold">]</TextBlock>
|
||||
</StackPanel>
|
||||
<TextBlock Grid.Column="1" Text="{Binding PropertyDescription.Name}" ToolTip.Tip="{Binding PropertyDescription.Description}" />
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="{Binding CountDisplay, Mode=OneWay}"
|
||||
FontFamily="Consolas"
|
||||
HorizontalAlignment="Right" />
|
||||
</Grid>
|
||||
</TreeDataTemplate>
|
||||
<TreeDataTemplate DataType="{x:Type dataModel:DataModelPropertyViewModel}">
|
||||
<Grid ColumnDefinitions="Auto,Auto,*">
|
||||
|
||||
<!-- Value description -->
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0 0 5 0">
|
||||
<TextBlock FontWeight="Bold">[</TextBlock>
|
||||
<TextBlock FontWeight="Bold" Text="{Binding DisplayValueType, Converter={StaticResource TypeToStringConverter}, Mode=OneWay}" />
|
||||
<TextBlock FontWeight="Bold">]</TextBlock>
|
||||
</StackPanel>
|
||||
<TextBlock Grid.Column="1" Text="{Binding PropertyDescription.Name}" ToolTip.Tip="{Binding PropertyDescription.Description}" />
|
||||
|
||||
<!-- Value display -->
|
||||
<ContentControl Grid.Column="2" Content="{Binding DisplayViewModel}" FontFamily="Consolas" />
|
||||
</Grid>
|
||||
</TreeDataTemplate>
|
||||
<TreeDataTemplate DataType="{x:Type dataModel:DataModelListItemViewModel}">
|
||||
<Grid ColumnDefinitions="Auto,Auto,*">
|
||||
<!-- Value description -->
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0 0 5 0">
|
||||
<TextBlock FontWeight="Bold">[</TextBlock>
|
||||
<TextBlock FontWeight="Bold" Text="{Binding ListType, Converter={StaticResource TypeToStringConverter}}" />
|
||||
<TextBlock FontWeight="Bold">]</TextBlock>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal" Margin="0 0 5 0">
|
||||
<TextBlock>List item #</TextBlock>
|
||||
<TextBlock Text="{Binding Index, Mode=OneWay}" />
|
||||
</StackPanel>
|
||||
|
||||
<!-- Value display -->
|
||||
<ContentControl Grid.Column="2" Content="{Binding DisplayViewModel}" FontFamily="Consolas" />
|
||||
</Grid>
|
||||
</TreeDataTemplate>
|
||||
|
||||
<TreeDataTemplate DataType="{x:Type dataModel:DataModelEventViewModel}" ItemsSource="{Binding Children}">
|
||||
<Grid ColumnDefinitions="Auto,Auto,*">
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0 0 5 0">
|
||||
<TextBlock FontWeight="Bold">[</TextBlock>
|
||||
<TextBlock FontWeight="Bold" Text="{Binding DisplayValueType, Converter={StaticResource TypeToStringConverter}, Mode=OneWay}" />
|
||||
<TextBlock FontWeight="Bold">]</TextBlock>
|
||||
</StackPanel>
|
||||
<TextBlock Grid.Column="1" Text="{Binding PropertyDescription.Name}" ToolTip.Tip="{Binding PropertyDescription.Description}" />
|
||||
<TextBlock Grid.Column="2"
|
||||
Text="{Binding CountDisplay, Mode=OneWay}"
|
||||
FontFamily="Consolas"
|
||||
HorizontalAlignment="Right" />
|
||||
</Grid>
|
||||
</TreeDataTemplate>
|
||||
</TreeView.DataTemplates>
|
||||
</TreeView>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
@@ -0,0 +1,18 @@
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Debugger.DataModel
|
||||
{
|
||||
public class DataModelDebugView : ReactiveUserControl<DataModelDebugViewModel>
|
||||
{
|
||||
public DataModelDebugView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,148 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.DataModelVisualization.Shared;
|
||||
using Artemis.UI.Shared.Services.Interfaces;
|
||||
using Avalonia.Threading;
|
||||
using DynamicData;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Debugger.DataModel;
|
||||
|
||||
public class DataModelDebugViewModel : ActivatableViewModelBase, IRoutableViewModel
|
||||
{
|
||||
private readonly IDataModelUIService _dataModelUIService;
|
||||
private readonly IPluginManagementService _pluginManagementService;
|
||||
private readonly DispatcherTimer _updateTimer;
|
||||
|
||||
private bool _isModuleFilterEnabled;
|
||||
private DataModelPropertiesViewModel? _mainDataModel;
|
||||
private string? _propertySearch;
|
||||
private Module? _selectedModule;
|
||||
private bool _slowUpdates;
|
||||
|
||||
public DataModelDebugViewModel(IScreen hostScreen, IDataModelUIService dataModelUIService, IPluginManagementService pluginManagementService)
|
||||
{
|
||||
_dataModelUIService = dataModelUIService;
|
||||
_pluginManagementService = pluginManagementService;
|
||||
_updateTimer = new DispatcherTimer(TimeSpan.FromMilliseconds(25), DispatcherPriority.Normal, (_, _) => Update());
|
||||
|
||||
HostScreen = hostScreen;
|
||||
Modules = new ObservableCollection<Module>();
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
Observable.FromEventPattern<PluginFeatureEventArgs>(x => pluginManagementService.PluginFeatureEnabled += x, x => pluginManagementService.PluginFeatureEnabled -= x)
|
||||
.Subscribe(d => PluginFeatureToggled(d.EventArgs.PluginFeature))
|
||||
.DisposeWith(disposables);
|
||||
Observable.FromEventPattern<PluginFeatureEventArgs>(x => pluginManagementService.PluginFeatureDisabled += x, x => pluginManagementService.PluginFeatureDisabled -= x)
|
||||
.Subscribe(d => PluginFeatureToggled(d.EventArgs.PluginFeature))
|
||||
.DisposeWith(disposables);
|
||||
|
||||
GetDataModel();
|
||||
_updateTimer.Start();
|
||||
Disposable.Create(() => _updateTimer.Stop()).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
public DataModelPropertiesViewModel? MainDataModel
|
||||
{
|
||||
get => _mainDataModel;
|
||||
set => RaiseAndSetIfChanged(ref _mainDataModel, value);
|
||||
}
|
||||
|
||||
public string? PropertySearch
|
||||
{
|
||||
get => _propertySearch;
|
||||
set => RaiseAndSetIfChanged(ref _propertySearch, value);
|
||||
}
|
||||
|
||||
public bool SlowUpdates
|
||||
{
|
||||
get => _slowUpdates;
|
||||
set
|
||||
{
|
||||
RaiseAndSetIfChanged(ref _slowUpdates, value);
|
||||
_updateTimer.Interval = TimeSpan.FromMilliseconds(_slowUpdates ? 500 : 25);
|
||||
}
|
||||
}
|
||||
|
||||
public ObservableCollection<Module> Modules { get; }
|
||||
|
||||
public Module? SelectedModule
|
||||
{
|
||||
get => _selectedModule;
|
||||
set
|
||||
{
|
||||
RaiseAndSetIfChanged(ref _selectedModule, value);
|
||||
GetDataModel();
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsModuleFilterEnabled
|
||||
{
|
||||
get => _isModuleFilterEnabled;
|
||||
set
|
||||
{
|
||||
RaiseAndSetIfChanged(ref _isModuleFilterEnabled, value);
|
||||
|
||||
if (!IsModuleFilterEnabled)
|
||||
SelectedModule = null;
|
||||
else
|
||||
GetDataModel();
|
||||
}
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (MainDataModel == null)
|
||||
return;
|
||||
|
||||
lock (MainDataModel)
|
||||
{
|
||||
MainDataModel.Update(_dataModelUIService, new DataModelUpdateConfiguration(true));
|
||||
}
|
||||
}
|
||||
|
||||
private void PluginFeatureToggled(PluginFeature pluginFeature)
|
||||
{
|
||||
if (pluginFeature is Module)
|
||||
PopulateModules();
|
||||
}
|
||||
|
||||
private void GetDataModel()
|
||||
{
|
||||
MainDataModel = SelectedModule != null
|
||||
? _dataModelUIService.GetPluginDataModelVisualization(new List<Module> {SelectedModule}, false)
|
||||
: _dataModelUIService.GetMainDataModelVisualization();
|
||||
}
|
||||
|
||||
private void PopulateModules()
|
||||
{
|
||||
Modules.Clear();
|
||||
Modules.AddRange(_pluginManagementService.GetFeaturesOfType<Module>().Where(p => p.IsEnabled).OrderBy(m => m.Info.Name));
|
||||
|
||||
if (MainDataModel == null)
|
||||
return;
|
||||
|
||||
if (SelectedModule == null)
|
||||
{
|
||||
if (MainDataModel != null)
|
||||
_dataModelUIService.UpdateModules(MainDataModel);
|
||||
}
|
||||
else if (!SelectedModule.IsEnabled)
|
||||
{
|
||||
SelectedModule = null;
|
||||
}
|
||||
}
|
||||
|
||||
public string UrlPathSegment => "data-model";
|
||||
public IScreen HostScreen { get; }
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.UI.Screens.Debugger.Logs.LogsDebugView">
|
||||
<StackPanel>
|
||||
<TextBlock Classes="h3">Logs</TextBlock>
|
||||
<TextBlock TextWrapping="Wrap">
|
||||
On this page you can view Artemis's logs in real-time. Logging can come from Artemis itself, plugins and scripts.
|
||||
</TextBlock>
|
||||
|
||||
<TextBlock Margin="0 20 0 0">TODO as there's no FlowDocumentScrollViewer in Avalonia and I'm too lazy to come up with an alternative.</TextBlock>
|
||||
<TextBlock Classes="subtitle">#feelsbadman</TextBlock>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,18 @@
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Debugger.Logs
|
||||
{
|
||||
public class LogsDebugView : ReactiveUserControl<LogsDebugViewModel>
|
||||
{
|
||||
public LogsDebugView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Artemis.UI.Shared;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Debugger.Logs
|
||||
{
|
||||
public class LogsDebugViewModel : ActivatableViewModelBase, IRoutableViewModel
|
||||
{
|
||||
public LogsDebugViewModel(IScreen hostScreen)
|
||||
{
|
||||
HostScreen = hostScreen;
|
||||
}
|
||||
|
||||
public string UrlPathSegment => "logs";
|
||||
public IScreen HostScreen { get; }
|
||||
}
|
||||
}
|
||||
+61
@@ -0,0 +1,61 @@
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Debugger.Performance
|
||||
{
|
||||
public class PerformanceDebugMeasurementViewModel : ViewModelBase
|
||||
{
|
||||
private string? _average;
|
||||
private string? _last;
|
||||
private string? _max;
|
||||
private string? _min;
|
||||
private string? _percentile;
|
||||
|
||||
public PerformanceDebugMeasurementViewModel(ProfilingMeasurement measurement)
|
||||
{
|
||||
Measurement = measurement;
|
||||
}
|
||||
|
||||
public ProfilingMeasurement Measurement { get; }
|
||||
|
||||
public string? Last
|
||||
{
|
||||
get => _last;
|
||||
set => RaiseAndSetIfChanged(ref _last, value);
|
||||
}
|
||||
|
||||
public string? Average
|
||||
{
|
||||
get => _average;
|
||||
set => RaiseAndSetIfChanged(ref _average, value);
|
||||
}
|
||||
|
||||
public string? Min
|
||||
{
|
||||
get => _min;
|
||||
set => RaiseAndSetIfChanged(ref _min, value);
|
||||
}
|
||||
|
||||
public string? Max
|
||||
{
|
||||
get => _max;
|
||||
set => RaiseAndSetIfChanged(ref _max, value);
|
||||
}
|
||||
|
||||
public string? Percentile
|
||||
{
|
||||
get => _percentile;
|
||||
set => RaiseAndSetIfChanged(ref _percentile, value);
|
||||
}
|
||||
|
||||
public void Update()
|
||||
{
|
||||
Last = Measurement.GetLast().TotalMilliseconds + " ms";
|
||||
Average = Measurement.GetAverage().TotalMilliseconds + " ms";
|
||||
Min = Measurement.GetMin().TotalMilliseconds + " ms";
|
||||
Max = Measurement.GetMax().TotalMilliseconds + " ms";
|
||||
Percentile = Measurement.GetPercentile(0.95).TotalMilliseconds + " ms";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:controls="clr-namespace:Artemis.UI.Shared.Controls;assembly=Artemis.UI.Shared"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.UI.Screens.Debugger.Performance.PerformanceDebugPluginView">
|
||||
<Border Classes="card-condensed" Margin="0 5">
|
||||
<StackPanel>
|
||||
<Grid ColumnDefinitions="40,*">
|
||||
<controls:ArtemisIcon Grid.Column="0" Icon="{Binding Plugin.Info.ResolvedIcon}" Width="24" Height="24" />
|
||||
<TextBlock Grid.Column="1" VerticalAlignment="Center" Classes="h5" Text="{Binding Plugin.Info.Name}" />
|
||||
</Grid>
|
||||
|
||||
<ItemsControl Items="{Binding Profilers}"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,18 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace Artemis.UI.Screens.Debugger.Performance
|
||||
{
|
||||
public partial class PerformanceDebugPluginView : UserControl
|
||||
{
|
||||
public PerformanceDebugPluginView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared;
|
||||
|
||||
namespace Artemis.UI.Screens.Debugger.Performance
|
||||
{
|
||||
public class PerformanceDebugPluginViewModel : ViewModelBase
|
||||
{
|
||||
public PerformanceDebugPluginViewModel(Plugin plugin)
|
||||
{
|
||||
Plugin = plugin;
|
||||
}
|
||||
|
||||
public Plugin Plugin { get; }
|
||||
|
||||
public ObservableCollection<PerformanceDebugProfilerViewModel> Profilers { get; } = new();
|
||||
|
||||
public void Update()
|
||||
{
|
||||
foreach (Profiler pluginProfiler in Plugin.Profilers.Where(p => p.Measurements.Any()))
|
||||
{
|
||||
if (Profilers.All(p => p.Profiler != pluginProfiler))
|
||||
Profilers.Add(new PerformanceDebugProfilerViewModel(pluginProfiler));
|
||||
}
|
||||
|
||||
foreach (PerformanceDebugProfilerViewModel profilerViewModel in Profilers)
|
||||
profilerViewModel.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Debugger.Performance"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.UI.Screens.Debugger.Performance.PerformanceDebugProfilerView">
|
||||
<StackPanel>
|
||||
<TextBlock Classes="subtitle" Text="{Binding Profiler.Name}" Margin="10 10 0 0" />
|
||||
|
||||
<DataGrid Items="{Binding Measurements}"
|
||||
d:DataContext="{d:DesignInstance Type={x:Type local:PerformanceDebugMeasurementViewModel}}"
|
||||
CanUserSortColumns="True"
|
||||
IsReadOnly="True"
|
||||
AutoGenerateColumns="False"
|
||||
CanUserReorderColumns="False"
|
||||
CanUserResizeColumns="False"
|
||||
Margin="10 5 10 10">
|
||||
<DataGrid.Columns>
|
||||
<DataGridTextColumn Binding="{Binding Measurement.Identifier}" Header="Identifier" />
|
||||
<DataGridTextColumn Binding="{Binding Last}" Header="Last" />
|
||||
<DataGridTextColumn Binding="{Binding Min}" Header="Min" />
|
||||
<DataGridTextColumn Binding="{Binding Max}" Header="Max" />
|
||||
<DataGridTextColumn Binding="{Binding Average}" Header="Average" />
|
||||
<DataGridTextColumn Binding="{Binding Percentile}" Header="95th percentile" />
|
||||
</DataGrid.Columns>
|
||||
</DataGrid>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
using Avalonia.Controls;
|
||||
using Avalonia.Markup.Xaml;
|
||||
|
||||
namespace Artemis.UI.Screens.Debugger.Performance
|
||||
{
|
||||
public partial class PerformanceDebugProfilerView : UserControl
|
||||
{
|
||||
public PerformanceDebugProfilerView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Shared;
|
||||
|
||||
namespace Artemis.UI.Screens.Debugger.Performance
|
||||
{
|
||||
public class PerformanceDebugProfilerViewModel : ViewModelBase
|
||||
{
|
||||
public PerformanceDebugProfilerViewModel(Profiler profiler)
|
||||
{
|
||||
Profiler = profiler;
|
||||
}
|
||||
|
||||
public Profiler Profiler { get; }
|
||||
|
||||
public ObservableCollection<PerformanceDebugMeasurementViewModel> Measurements { get; } = new();
|
||||
|
||||
public void Update()
|
||||
{
|
||||
foreach ((string _, ProfilingMeasurement measurement) in Profiler.Measurements)
|
||||
{
|
||||
if (Measurements.All(m => m.Measurement != measurement))
|
||||
Measurements.Add(new PerformanceDebugMeasurementViewModel(measurement));
|
||||
}
|
||||
|
||||
foreach (PerformanceDebugMeasurementViewModel profilingMeasurementViewModel in Measurements)
|
||||
profilingMeasurementViewModel.Update();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns: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">
|
||||
<Grid RowDefinitions="Auto,Auto,*">
|
||||
<StackPanel Grid.Row="0">
|
||||
<TextBlock Classes="h3">Performance</TextBlock>
|
||||
<TextBlock TextWrapping="Wrap">
|
||||
On this page you can see how much CPU time different plugin features are taking. If you are having performance issues, below you can find out which plugin might be the culprit.
|
||||
</TextBlock>
|
||||
<Grid ColumnDefinitions="*,Auto">
|
||||
<TextBlock TextWrapping="Wrap" Classes="subtitle" Margin="0 10">
|
||||
These performance stats are rather basic, for advanced performance profiling check out the wiki.
|
||||
</TextBlock>
|
||||
<controls:HyperlinkButton Grid.Column="1" NavigateUri="https://wiki.artemis-rgb.com/en/guides/user/plugins/profiling">
|
||||
JetBrains Profiling Guide
|
||||
</controls:HyperlinkButton>
|
||||
</Grid>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Grid.Row="1" Orientation="Horizontal" HorizontalAlignment="Right" Margin="10 0">
|
||||
<TextBlock Text="FPS: " />
|
||||
<TextBlock FontWeight="Bold" Text="{Binding CurrentFps}" />
|
||||
<TextBlock Text=" at " />
|
||||
<TextBlock Text="{Binding RenderWidth}" />
|
||||
<TextBlock Text="x" />
|
||||
<TextBlock Text="{Binding RenderHeight}" />
|
||||
<TextBlock Text=" - Renderer: "></TextBlock>
|
||||
<TextBlock Text="{Binding Renderer}"></TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
|
||||
<ScrollViewer Grid.Row="2" VerticalScrollBarVisibility="Auto">
|
||||
<ItemsControl Items="{Binding Items}" Margin="0 0 10 0" />
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
@@ -0,0 +1,18 @@
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Debugger.Performance
|
||||
{
|
||||
public class PerformanceDebugView : ReactiveUserControl<PerformanceDebugViewModel>
|
||||
{
|
||||
public PerformanceDebugView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
using System;
|
||||
using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Reactive.Disposables;
|
||||
using System.Reactive.Linq;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Shared;
|
||||
using Avalonia.Threading;
|
||||
using ReactiveUI;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.UI.Screens.Debugger.Performance;
|
||||
|
||||
public class PerformanceDebugViewModel : ActivatableViewModelBase, IRoutableViewModel
|
||||
{
|
||||
private readonly ICoreService _coreService;
|
||||
private readonly IPluginManagementService _pluginManagementService;
|
||||
private readonly DispatcherTimer _updateTimer;
|
||||
private double _currentFps;
|
||||
private string? _renderer;
|
||||
private int _renderHeight;
|
||||
private int _renderWidth;
|
||||
|
||||
public PerformanceDebugViewModel(IScreen hostScreen, ICoreService coreService, IPluginManagementService pluginManagementService)
|
||||
{
|
||||
HostScreen = hostScreen;
|
||||
_coreService = coreService;
|
||||
_pluginManagementService = pluginManagementService;
|
||||
_updateTimer = new DispatcherTimer(TimeSpan.FromMilliseconds(500), DispatcherPriority.Normal, (_, _) => Update());
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
Observable.FromEventPattern<PluginFeatureEventArgs>(x => pluginManagementService.PluginFeatureEnabled += x, x => pluginManagementService.PluginFeatureEnabled -= x)
|
||||
.Subscribe(_ => Repopulate())
|
||||
.DisposeWith(disposables);
|
||||
Observable.FromEventPattern<PluginFeatureEventArgs>(x => pluginManagementService.PluginFeatureDisabled += x, x => pluginManagementService.PluginFeatureDisabled -= x)
|
||||
.Subscribe(_ => Repopulate())
|
||||
.DisposeWith(disposables);
|
||||
Observable.FromEventPattern<PluginEventArgs>(x => pluginManagementService.PluginEnabled += x, x => pluginManagementService.PluginEnabled -= x)
|
||||
.Subscribe(_ => Repopulate())
|
||||
.DisposeWith(disposables);
|
||||
Observable.FromEventPattern<PluginEventArgs>(x => pluginManagementService.PluginDisabled += x, x => pluginManagementService.PluginDisabled -= x)
|
||||
.Subscribe(_ => Repopulate())
|
||||
.DisposeWith(disposables);
|
||||
|
||||
HandleActivation();
|
||||
PopulateItems();
|
||||
_updateTimer.Start();
|
||||
|
||||
Disposable.Create(() =>
|
||||
{
|
||||
_updateTimer.Stop();
|
||||
Items.Clear();
|
||||
HandleDeactivation();
|
||||
}).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
public ObservableCollection<PerformanceDebugPluginViewModel> Items { get; } = new();
|
||||
|
||||
public double CurrentFps
|
||||
{
|
||||
get => _currentFps;
|
||||
set => RaiseAndSetIfChanged(ref _currentFps, value);
|
||||
}
|
||||
|
||||
public int RenderWidth
|
||||
{
|
||||
get => _renderWidth;
|
||||
set => RaiseAndSetIfChanged(ref _renderWidth, value);
|
||||
}
|
||||
|
||||
public int RenderHeight
|
||||
{
|
||||
get => _renderHeight;
|
||||
set => RaiseAndSetIfChanged(ref _renderHeight, value);
|
||||
}
|
||||
|
||||
public string? Renderer
|
||||
{
|
||||
get => _renderer;
|
||||
set => 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)))
|
||||
Items.Add(performanceDebugPluginViewModel);
|
||||
}
|
||||
|
||||
private void Repopulate()
|
||||
{
|
||||
Items.Clear();
|
||||
PopulateItems();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
public string UrlPathSegment => "performance";
|
||||
public IScreen HostScreen { get; }
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.UI.Screens.Debugger.Render.RenderDebugView">
|
||||
<StackPanel>
|
||||
<TextBlock Classes="h3">Render</TextBlock>
|
||||
<TextBlock TextWrapping="Wrap">
|
||||
On this page you can view what Artemis renders to devices in real time. Artemis will overlay this image on your devices, taking the average of each pixel covering a LED, resulting the image appearing on your devices.
|
||||
</TextBlock>
|
||||
<TextBlock TextWrapping="Wrap" Classes="subtitle" Margin="0 10">
|
||||
Please note that having this window open can have a performance impact on your system.
|
||||
</TextBlock>
|
||||
|
||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
|
||||
<TextBlock Text="FPS: " />
|
||||
<TextBlock FontWeight="Bold" Text="{Binding CurrentFps}" />
|
||||
<TextBlock Text=" at " />
|
||||
<TextBlock Text="{Binding RenderWidth}" />
|
||||
<TextBlock Text="x" />
|
||||
<TextBlock Text="{Binding RenderHeight}" />
|
||||
<TextBlock Text=" - Renderer: "></TextBlock>
|
||||
<TextBlock Text="{Binding Renderer}"></TextBlock>
|
||||
</StackPanel>
|
||||
|
||||
<Border Classes="card" Padding="10">
|
||||
<ZoomBorder Name="ZoomBorder"
|
||||
Stretch="None"
|
||||
ClipToBounds="True"
|
||||
Focusable="True"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch">
|
||||
<Image Name="Visualization" Source="{Binding CurrentFrame}">
|
||||
<Image.Transitions>
|
||||
<Transitions>
|
||||
<TransformOperationsTransition Property="RenderTransform" Duration="0:0:0.2" Easing="CubicEaseOut"/>
|
||||
</Transitions>
|
||||
</Image.Transitions>
|
||||
</Image>
|
||||
</ZoomBorder>
|
||||
</Border>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,18 @@
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Debugger.Render
|
||||
{
|
||||
public class RenderDebugView : ReactiveUserControl<RenderDebugViewModel>
|
||||
{
|
||||
public RenderDebugView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,108 @@
|
||||
using System.IO;
|
||||
using System.Reactive.Disposables;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Shared;
|
||||
using Avalonia.Media.Imaging;
|
||||
using ReactiveUI;
|
||||
using SkiaSharp;
|
||||
|
||||
namespace Artemis.UI.Screens.Debugger.Render
|
||||
{
|
||||
public class RenderDebugViewModel : ActivatableViewModelBase, IRoutableViewModel
|
||||
{
|
||||
private readonly ICoreService _coreService;
|
||||
private double _currentFps;
|
||||
|
||||
private Bitmap? _currentFrame;
|
||||
private string? _frameTargetPath;
|
||||
private string? _renderer;
|
||||
private int _renderHeight;
|
||||
private int _renderWidth;
|
||||
|
||||
public RenderDebugViewModel(DebugViewModel hostScreen, ICoreService coreService)
|
||||
{
|
||||
HostScreen = hostScreen;
|
||||
_coreService = coreService;
|
||||
|
||||
this.WhenActivated(disposables =>
|
||||
{
|
||||
HandleActivation();
|
||||
Disposable.Create(HandleDeactivation).DisposeWith(disposables);
|
||||
});
|
||||
}
|
||||
|
||||
public Bitmap? CurrentFrame
|
||||
{
|
||||
get => _currentFrame;
|
||||
set => RaiseAndSetIfChanged(ref _currentFrame, value);
|
||||
}
|
||||
|
||||
public double CurrentFps
|
||||
{
|
||||
get => _currentFps;
|
||||
set => RaiseAndSetIfChanged(ref _currentFps, value);
|
||||
}
|
||||
|
||||
public int RenderWidth
|
||||
{
|
||||
get => _renderWidth;
|
||||
set => RaiseAndSetIfChanged(ref _renderWidth, value);
|
||||
}
|
||||
|
||||
public int RenderHeight
|
||||
{
|
||||
get => _renderHeight;
|
||||
set => RaiseAndSetIfChanged(ref _renderHeight, value);
|
||||
}
|
||||
|
||||
public string? Renderer
|
||||
{
|
||||
get => _renderer;
|
||||
set => 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 CoreServiceOnFrameRendered(object? sender, FrameRenderedEventArgs e)
|
||||
{
|
||||
CurrentFps = _coreService.FrameRate;
|
||||
using SKImage skImage = e.Texture.Surface.Snapshot();
|
||||
SKImageInfo bitmapInfo = e.Texture.ImageInfo;
|
||||
|
||||
if (_frameTargetPath != null)
|
||||
{
|
||||
using (SKData data = skImage.Encode(SKEncodedImageFormat.Png, 100))
|
||||
{
|
||||
using (FileStream stream = File.OpenWrite(_frameTargetPath))
|
||||
{
|
||||
data.SaveTo(stream);
|
||||
}
|
||||
}
|
||||
|
||||
_frameTargetPath = null;
|
||||
}
|
||||
|
||||
RenderHeight = bitmapInfo.Height;
|
||||
RenderWidth = bitmapInfo.Width;
|
||||
|
||||
// TODO: This performs well enough but look into something else
|
||||
using (SKData data = skImage.Encode(SKEncodedImageFormat.Png, 100))
|
||||
{
|
||||
CurrentFrame = new Bitmap(data.AsStream());
|
||||
}
|
||||
}
|
||||
|
||||
public string UrlPathSegment => "render";
|
||||
public IScreen HostScreen { get; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
<UserControl xmlns="https://github.com/avaloniaui"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
|
||||
x:Class="Artemis.UI.Screens.Debugger.Settings.DebugSettingsView">
|
||||
<TextBlock>Settings</TextBlock>
|
||||
</UserControl>
|
||||
@@ -0,0 +1,18 @@
|
||||
using Avalonia.Markup.Xaml;
|
||||
using Avalonia.ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Debugger.Settings
|
||||
{
|
||||
public class DebugSettingsView : ReactiveUserControl<DebugSettingsViewModel>
|
||||
{
|
||||
public DebugSettingsView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void InitializeComponent()
|
||||
{
|
||||
AvaloniaXamlLoader.Load(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
using Artemis.UI.Shared;
|
||||
using ReactiveUI;
|
||||
|
||||
namespace Artemis.UI.Screens.Debugger.Settings
|
||||
{
|
||||
public class DebugSettingsViewModel : ActivatableViewModelBase, IRoutableViewModel
|
||||
{
|
||||
public DebugSettingsViewModel(IScreen hostScreen)
|
||||
{
|
||||
HostScreen = hostScreen;
|
||||
}
|
||||
|
||||
public string UrlPathSegment => "logs";
|
||||
public IScreen HostScreen { get; }
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user