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

Debugger - Replaced NavigationView in favor for something simpler

This commit is contained in:
Robert 2022-08-07 16:19:41 +02:00
parent faf5302975
commit 87e87ae15d
35 changed files with 452 additions and 3293 deletions

View File

@ -1,18 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="BenchmarkDotNet" Version="0.13.1" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" />
</ItemGroup>
</Project>

View File

@ -1,40 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Artemis.Core;
using BenchmarkDotNet.Attributes;
namespace Artemis.Benchmarking
{
public class NumericConversion
{
private readonly float _float;
private readonly Numeric _numeric;
public NumericConversion()
{
_float = 255235235f;
_numeric = new Numeric(_float);
}
[Benchmark]
public void FloatToIntCast()
{
var integer = (int) _float;
}
[Benchmark]
public void NumericToIntCast()
{
var integer = (int) _numeric;
}
[Benchmark]
public void NumericToIntConvertTo()
{
var integer = Convert.ChangeType(_numeric, typeof(int));
}
}
}

View File

@ -1,3 +0,0 @@
using BenchmarkDotNet.Running;
BenchmarkRunner.Run(typeof(Program).Assembly);

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1668,10 +1668,7 @@
"Unosquare.Swan.Lite": { "Unosquare.Swan.Lite": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.0.0", "resolved": "3.0.0",
"contentHash": "noPwJJl1Q9uparXy1ogtkmyAPGNfSGb0BLT1292nFH1jdMKje6o2kvvrQUvF9Xklj+IoiAI0UzF6Aqxlvo10lw==", "contentHash": "noPwJJl1Q9uparXy1ogtkmyAPGNfSGb0BLT1292nFH1jdMKje6o2kvvrQUvF9Xklj+IoiAI0UzF6Aqxlvo10lw=="
"dependencies": {
"System.ValueTuple": "4.5.0"
}
}, },
"artemis.core": { "artemis.core": {
"type": "Project", "type": "Project",

View File

@ -1668,10 +1668,7 @@
"Unosquare.Swan.Lite": { "Unosquare.Swan.Lite": {
"type": "Transitive", "type": "Transitive",
"resolved": "3.0.0", "resolved": "3.0.0",
"contentHash": "noPwJJl1Q9uparXy1ogtkmyAPGNfSGb0BLT1292nFH1jdMKje6o2kvvrQUvF9Xklj+IoiAI0UzF6Aqxlvo10lw==", "contentHash": "noPwJJl1Q9uparXy1ogtkmyAPGNfSGb0BLT1292nFH1jdMKje6o2kvvrQUvF9Xklj+IoiAI0UzF6Aqxlvo10lw=="
"dependencies": {
"System.ValueTuple": "4.5.0"
}
}, },
"artemis.core": { "artemis.core": {
"type": "Project", "type": "Project",

View File

@ -1,4 +1,5 @@
using System; using System;
using System.Text.RegularExpressions;
using Avalonia; using Avalonia;
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Layout; using Avalonia.Layout;
@ -17,6 +18,7 @@ namespace Artemis.UI.Shared
/// </summary> /// </summary>
public class ArtemisIcon : UserControl public class ArtemisIcon : UserControl
{ {
private static Regex _imageRegex = new(@"[\/.](gif|jpg|jpeg|tiff|png)$", RegexOptions.Compiled);
/// <summary> /// <summary>
/// Creates a new instance of the <see cref="ArtemisIcon" /> class. /// Creates a new instance of the <see cref="ArtemisIcon" /> class.
/// </summary> /// </summary>
@ -39,9 +41,7 @@ namespace Artemis.UI.Shared
{ {
// First look for an enum value instead of a string // First look for an enum value instead of a string
if (Icon is MaterialIconKind materialIcon) if (Icon is MaterialIconKind materialIcon)
{
Content = new MaterialIcon {Kind = materialIcon, Width = Bounds.Width, Height = Bounds.Height}; Content = new MaterialIcon {Kind = materialIcon, Width = Bounds.Width, Height = Bounds.Height};
}
// If it's a string there are several options // If it's a string there are several options
else if (Icon is string iconString) else if (Icon is string iconString)
{ {
@ -49,7 +49,7 @@ namespace Artemis.UI.Shared
if (Enum.TryParse(iconString, true, out MaterialIconKind parsedIcon)) if (Enum.TryParse(iconString, true, out MaterialIconKind parsedIcon))
Content = new MaterialIcon {Kind = parsedIcon, Width = Bounds.Width, Height = Bounds.Height}; Content = new MaterialIcon {Kind = parsedIcon, Width = Bounds.Width, Height = Bounds.Height};
// An URI pointing to an image // An URI pointing to an image
else else if (_imageRegex.IsMatch(iconString))
{ {
if (!Fill) if (!Fill)
{ {
@ -71,6 +71,8 @@ namespace Artemis.UI.Shared
}; };
} }
} }
else
Content = new MaterialIcon {Kind = MaterialIconKind.QuestionMark, Width = Bounds.Width, Height = Bounds.Height};
} }
} }
catch catch

View File

@ -1,16 +1,19 @@
<controls:CoreWindow xmlns="https://github.com/avaloniaui" <controls:CoreWindow xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia" xmlns:controls="clr-namespace:FluentAvalonia.UI.Controls;assembly=FluentAvalonia"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
xmlns:reactiveUi="http://reactiveui.net" xmlns:reactiveUi="http://reactiveui.net"
mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="800" xmlns:debugger="clr-namespace:Artemis.UI.Screens.Debugger"
x:Class="Artemis.UI.Screens.Debugger.DebugView" xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
Icon="/Assets/Images/Logo/application.ico" mc:Ignorable="d" d:DesignWidth="1200" d:DesignHeight="800"
Title="Artemis | Debugger" x:Class="Artemis.UI.Screens.Debugger.DebugView"
Width="1200" x:DataType="debugger:DebugViewModel"
Height="800"> Icon="/Assets/Images/Logo/application.ico"
Title="Artemis | Debugger"
Width="1200"
Height="800">
<Window.Styles> <Window.Styles>
<Style Selector="StackPanel.sidebar-stackpanel avalonia|MaterialIcon"> <Style Selector="StackPanel.sidebar-stackpanel avalonia|MaterialIcon">
@ -21,55 +24,18 @@
</Style> </Style>
</Window.Styles> </Window.Styles>
<Panel> <Grid ColumnDefinitions="240,*">
<controls:NavigationView x:Name="Navigation" <ListBox Items="{CompiledBinding Items}" SelectedItem="{CompiledBinding SelectedItem}" Grid.Column="0" Margin="10">
SelectedItem="{Binding SelectedItem}" <ListBox.ItemTemplate>
IsPaneToggleButtonVisible="False" <DataTemplate x:DataType="shared:ViewModelBase">
PaneDisplayMode="Left" <TextBlock Text="{CompiledBinding DisplayName}" VerticalAlignment="Center" />
Margin="0 10 0 0"> </DataTemplate>
<controls:NavigationView.MenuItems> </ListBox.ItemTemplate>
<controls:NavigationViewItem Tag="Rendering"> </ListBox>
<controls:NavigationViewItem.Content> <Border Classes="router-container" Grid.Column="1">
<StackPanel Orientation="Horizontal" Classes="sidebar-stackpanel"> <ContentControl Content="{CompiledBinding SelectedItem}" Margin="15"></ContentControl>
<avalonia:MaterialIcon Kind="Paint" /> </Border>
<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"> <StackPanel Grid.Column="0" Grid.ColumnSpan="2" Classes="notification-container" Name="NotificationContainer" VerticalAlignment="Bottom" HorizontalAlignment="Right" />
<reactiveUi:RoutedViewHost.PageTransition> </Grid>
<CrossFade Duration="0.1" />
</reactiveUi:RoutedViewHost.PageTransition>
</reactiveUi:RoutedViewHost>
</controls:NavigationView>
<StackPanel Classes="notification-container" Name="NotificationContainer" VerticalAlignment="Bottom" HorizontalAlignment="Right"/>
</Panel>
</controls:CoreWindow> </controls:CoreWindow>

View File

@ -22,17 +22,13 @@ namespace Artemis.UI.Screens.Debugger
this.AttachDevTools(); this.AttachDevTools();
#endif #endif
NavigationView navigation = this.Get<NavigationView>("Navigation");
this.WhenActivated(d => this.WhenActivated(d =>
{ {
Observable.FromEventPattern(x => ViewModel!.ActivationRequested += x, x => ViewModel!.ActivationRequested -= x).Subscribe(_ => Observable.FromEventPattern(x => ViewModel!.ActivationRequested += x, x => ViewModel!.ActivationRequested -= x).Subscribe(_ =>
{ {
WindowState = WindowState.Normal; WindowState = WindowState.Normal;
Activate(); Activate();
}).DisposeWith(d); }).DisposeWith(d);
ViewModel!.SelectedItem = (NavigationViewItem) navigation.MenuItems.ElementAt(0);
}); });
} }

View File

@ -1,87 +1,51 @@
using System; using System;
using System.Collections.ObjectModel;
using System.Reactive.Disposables; using System.Reactive.Disposables;
using Artemis.UI.Screens.Debugger.DataModel; using Artemis.UI.Screens.Debugger.DataModel;
using Artemis.UI.Screens.Debugger.Logs; using Artemis.UI.Screens.Debugger.Logs;
using Artemis.UI.Screens.Debugger.Performance; using Artemis.UI.Screens.Debugger.Performance;
using Artemis.UI.Screens.Debugger.Render; using Artemis.UI.Screens.Debugger.Render;
using Artemis.UI.Screens.Debugger.Settings;
using Artemis.UI.Services.Interfaces; using Artemis.UI.Services.Interfaces;
using Artemis.UI.Shared; using Artemis.UI.Shared;
using FluentAvalonia.UI.Controls;
using Ninject;
using Ninject.Parameters;
using ReactiveUI; using ReactiveUI;
namespace Artemis.UI.Screens.Debugger namespace Artemis.UI.Screens.Debugger;
public class DebugViewModel : ActivatableViewModelBase, IScreen
{ {
public class DebugViewModel : ActivatableViewModelBase, IScreen private ViewModelBase _selectedItem;
public DebugViewModel(IDebugService debugService,
RenderDebugViewModel render,
DataModelDebugViewModel dataModel,
PerformanceDebugViewModel performance,
LogsDebugViewModel logs)
{ {
private readonly IKernel _kernel; Items = new ObservableCollection<ViewModelBase> {render, dataModel, performance, logs};
private readonly IDebugService _debugService; SelectedItem = render;
private NavigationViewItem? _selectedItem;
public DebugViewModel(IKernel kernel, IDebugService debugService) this.WhenActivated(d => Disposable.Create(debugService.ClearDebugger).DisposeWith(d));
{
_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);
}
} }
public ObservableCollection<ViewModelBase> Items { get; }
public ViewModelBase SelectedItem
{
get => _selectedItem;
set => RaiseAndSetIfChanged(ref _selectedItem, value);
}
public void Activate()
{
OnActivationRequested();
}
public event EventHandler? ActivationRequested;
protected virtual void OnActivationRequested()
{
ActivationRequested?.Invoke(this, EventArgs.Empty);
}
public RoutingState Router { get; } = new();
} }

View File

@ -21,102 +21,102 @@
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<TreeView Grid.Row="1" Items="{Binding MainDataModel.Children}"> <TreeView Grid.Row="1" Items="{Binding MainDataModel.Children}">
<TreeView.Styles> <TreeView.Styles>
<Style Selector="TreeViewItem"> <Style Selector="TreeViewItem">
<Setter Property="IsExpanded" Value="{Binding IsVisualizationExpanded, Mode=TwoWay}" /> <Setter Property="IsExpanded" Value="{Binding IsVisualizationExpanded, Mode=TwoWay}" />
<Setter Property="ContextFlyout"> <Setter Property="ContextFlyout">
<Setter.Value> <Setter.Value>
<MenuFlyout> <MenuFlyout>
<MenuItem Header="Copy path" Command="{Binding CopyPath}"> <MenuItem Header="Copy path" Command="{Binding CopyPath}">
<MenuItem.Icon> <MenuItem.Icon>
<avalonia:MaterialIcon Kind="ContentCopy" /> <avalonia:MaterialIcon Kind="ContentCopy" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
</MenuFlyout> </MenuFlyout>
</Setter.Value> </Setter.Value>
</Setter> </Setter>
</Style> </Style>
</TreeView.Styles> </TreeView.Styles>
<TreeView.DataTemplates> <TreeView.DataTemplates>
<TreeDataTemplate DataType="{x:Type dataModel:DataModelPropertiesViewModel}" ItemsSource="{Binding Children}"> <TreeDataTemplate DataType="{x:Type dataModel:DataModelPropertiesViewModel}" ItemsSource="{Binding Children}">
<Grid ColumnDefinitions="Auto,Auto,*"> <Grid ColumnDefinitions="Auto,Auto,*">
<StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0 0 5 0"> <StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0 0 5 0">
<TextBlock FontWeight="Bold">[</TextBlock> <TextBlock FontWeight="Bold">[</TextBlock>
<TextBlock FontWeight="Bold" Text="{Binding DisplayValueType, Converter={StaticResource TypeToStringConverter}, Mode=OneWay}" /> <TextBlock FontWeight="Bold" Text="{Binding DisplayValueType, Converter={StaticResource TypeToStringConverter}, Mode=OneWay}" />
<TextBlock FontWeight="Bold">]</TextBlock> <TextBlock FontWeight="Bold">]</TextBlock>
</StackPanel> </StackPanel>
<TextBlock Grid.Column="1" Text="{Binding PropertyDescription.Name}" ToolTip.Tip="{Binding PropertyDescription.Description}" /> <TextBlock Grid.Column="1" Text="{Binding PropertyDescription.Name}" ToolTip.Tip="{Binding PropertyDescription.Description}" />
<TextBlock Grid.Column="2" <TextBlock Grid.Column="2"
Text="{Binding DisplayValue}" Text="{Binding DisplayValue}"
FontFamily="Consolas" FontFamily="Consolas"
HorizontalAlignment="Right" /> HorizontalAlignment="Right" />
</Grid> </Grid>
</TreeDataTemplate> </TreeDataTemplate>
<TreeDataTemplate DataType="{x:Type dataModel:DataModelListViewModel}" ItemsSource="{Binding ListChildren}"> <TreeDataTemplate DataType="{x:Type dataModel:DataModelListViewModel}" ItemsSource="{Binding ListChildren}">
<Grid ColumnDefinitions="Auto,Auto,*"> <Grid ColumnDefinitions="Auto,Auto,*">
<StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0 0 5 0"> <StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0 0 5 0">
<TextBlock FontWeight="Bold">[</TextBlock> <TextBlock FontWeight="Bold">[</TextBlock>
<TextBlock FontWeight="Bold" Text="{Binding DisplayValueType, Converter={StaticResource TypeToStringConverter}, Mode=OneWay}" /> <TextBlock FontWeight="Bold" Text="{Binding DisplayValueType, Converter={StaticResource TypeToStringConverter}, Mode=OneWay}" />
<TextBlock FontWeight="Bold">]</TextBlock> <TextBlock FontWeight="Bold">]</TextBlock>
</StackPanel> </StackPanel>
<TextBlock Grid.Column="1" Text="{Binding PropertyDescription.Name}" ToolTip.Tip="{Binding PropertyDescription.Description}" /> <TextBlock Grid.Column="1" Text="{Binding PropertyDescription.Name}" ToolTip.Tip="{Binding PropertyDescription.Description}" />
<TextBlock Grid.Column="2" <TextBlock Grid.Column="2"
Text="{Binding CountDisplay, Mode=OneWay}" Text="{Binding CountDisplay, Mode=OneWay}"
FontFamily="Consolas" FontFamily="Consolas"
HorizontalAlignment="Right" /> HorizontalAlignment="Right" />
</Grid> </Grid>
</TreeDataTemplate> </TreeDataTemplate>
<TreeDataTemplate DataType="{x:Type dataModel:DataModelPropertyViewModel}"> <TreeDataTemplate DataType="{x:Type dataModel:DataModelPropertyViewModel}">
<Grid ColumnDefinitions="Auto,Auto,*"> <Grid ColumnDefinitions="Auto,Auto,*">
<!-- Value description --> <!-- Value description -->
<StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0 0 5 0"> <StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0 0 5 0">
<TextBlock FontWeight="Bold">[</TextBlock> <TextBlock FontWeight="Bold">[</TextBlock>
<TextBlock FontWeight="Bold" Text="{Binding DisplayValueType, Converter={StaticResource TypeToStringConverter}, Mode=OneWay}" /> <TextBlock FontWeight="Bold" Text="{Binding DisplayValueType, Converter={StaticResource TypeToStringConverter}, Mode=OneWay}" />
<TextBlock FontWeight="Bold">]</TextBlock> <TextBlock FontWeight="Bold">]</TextBlock>
</StackPanel> </StackPanel>
<TextBlock Grid.Column="1" Text="{Binding PropertyDescription.Name}" ToolTip.Tip="{Binding PropertyDescription.Description}" /> <TextBlock Grid.Column="1" Text="{Binding PropertyDescription.Name}" ToolTip.Tip="{Binding PropertyDescription.Description}" />
<!-- Value display --> <!-- Value display -->
<ContentControl Grid.Column="2" Content="{Binding DisplayViewModel}" FontFamily="Consolas" /> <ContentControl Grid.Column="2" Content="{Binding DisplayViewModel}" FontFamily="Consolas" />
</Grid> </Grid>
</TreeDataTemplate> </TreeDataTemplate>
<TreeDataTemplate DataType="{x:Type dataModel:DataModelListItemViewModel}"> <TreeDataTemplate DataType="{x:Type dataModel:DataModelListItemViewModel}">
<Grid ColumnDefinitions="Auto,Auto,*"> <Grid ColumnDefinitions="Auto,Auto,*">
<!-- Value description --> <!-- Value description -->
<StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0 0 5 0"> <StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0 0 5 0">
<TextBlock FontWeight="Bold">[</TextBlock> <TextBlock FontWeight="Bold">[</TextBlock>
<TextBlock FontWeight="Bold" Text="{Binding ListType, Converter={StaticResource TypeToStringConverter}}" /> <TextBlock FontWeight="Bold" Text="{Binding ListType, Converter={StaticResource TypeToStringConverter}}" />
<TextBlock FontWeight="Bold">]</TextBlock> <TextBlock FontWeight="Bold">]</TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Column="1" Orientation="Horizontal" Margin="0 0 5 0"> <StackPanel Grid.Column="1" Orientation="Horizontal" Margin="0 0 5 0">
<TextBlock>List item #</TextBlock> <TextBlock>List item #</TextBlock>
<TextBlock Text="{Binding Index, Mode=OneWay}" /> <TextBlock Text="{Binding Index, Mode=OneWay}" />
</StackPanel> </StackPanel>
<!-- Value display --> <!-- Value display -->
<ContentControl Grid.Column="2" Content="{Binding DisplayViewModel}" FontFamily="Consolas" /> <ContentControl Grid.Column="2" Content="{Binding DisplayViewModel}" FontFamily="Consolas" />
</Grid> </Grid>
</TreeDataTemplate> </TreeDataTemplate>
<TreeDataTemplate DataType="{x:Type dataModel:DataModelEventViewModel}" ItemsSource="{Binding Children}"> <TreeDataTemplate DataType="{x:Type dataModel:DataModelEventViewModel}" ItemsSource="{Binding Children}">
<Grid ColumnDefinitions="Auto,Auto,*"> <Grid ColumnDefinitions="Auto,Auto,*">
<StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0 0 5 0"> <StackPanel Grid.Column="0" Orientation="Horizontal" Margin="0 0 5 0">
<TextBlock FontWeight="Bold">[</TextBlock> <TextBlock FontWeight="Bold">[</TextBlock>
<TextBlock FontWeight="Bold" Text="{Binding DisplayValueType, Converter={StaticResource TypeToStringConverter}, Mode=OneWay}" /> <TextBlock FontWeight="Bold" Text="{Binding DisplayValueType, Converter={StaticResource TypeToStringConverter}, Mode=OneWay}" />
<TextBlock FontWeight="Bold">]</TextBlock> <TextBlock FontWeight="Bold">]</TextBlock>
</StackPanel> </StackPanel>
<TextBlock Grid.Column="1" Text="{Binding PropertyDescription.Name}" ToolTip.Tip="{Binding PropertyDescription.Description}" /> <TextBlock Grid.Column="1" Text="{Binding PropertyDescription.Name}" ToolTip.Tip="{Binding PropertyDescription.Description}" />
<TextBlock Grid.Column="2" <TextBlock Grid.Column="2"
Text="{Binding CountDisplay, Mode=OneWay}" Text="{Binding CountDisplay, Mode=OneWay}"
FontFamily="Consolas" FontFamily="Consolas"
HorizontalAlignment="Right" /> HorizontalAlignment="Right" />
</Grid> </Grid>
</TreeDataTemplate> </TreeDataTemplate>
</TreeView.DataTemplates> </TreeView.DataTemplates>
</TreeView> </TreeView>
</Grid> </Grid>
</UserControl> </UserControl>

View File

@ -1,18 +1,17 @@
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI; using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.Debugger.DataModel namespace Artemis.UI.Screens.Debugger.DataModel;
{
public class DataModelDebugView : ReactiveUserControl<DataModelDebugViewModel>
{
public DataModelDebugView()
{
InitializeComponent();
}
private void InitializeComponent() public class DataModelDebugView : ReactiveUserControl<DataModelDebugViewModel>
{ {
AvaloniaXamlLoader.Load(this); public DataModelDebugView()
} {
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
} }
} }

View File

@ -16,7 +16,7 @@ using ReactiveUI;
namespace Artemis.UI.Screens.Debugger.DataModel; namespace Artemis.UI.Screens.Debugger.DataModel;
public class DataModelDebugViewModel : ActivatableViewModelBase, IRoutableViewModel public class DataModelDebugViewModel : ActivatableViewModelBase
{ {
private readonly IDataModelUIService _dataModelUIService; private readonly IDataModelUIService _dataModelUIService;
private readonly IPluginManagementService _pluginManagementService; private readonly IPluginManagementService _pluginManagementService;
@ -28,15 +28,15 @@ public class DataModelDebugViewModel : ActivatableViewModelBase, IRoutableViewMo
private Module? _selectedModule; private Module? _selectedModule;
private bool _slowUpdates; private bool _slowUpdates;
public DataModelDebugViewModel(IScreen hostScreen, IDataModelUIService dataModelUIService, IPluginManagementService pluginManagementService) public DataModelDebugViewModel(IDataModelUIService dataModelUIService, IPluginManagementService pluginManagementService)
{ {
_dataModelUIService = dataModelUIService; _dataModelUIService = dataModelUIService;
_pluginManagementService = pluginManagementService; _pluginManagementService = pluginManagementService;
_updateTimer = new DispatcherTimer(TimeSpan.FromMilliseconds(25), DispatcherPriority.DataBind, (_, _) => Update()); _updateTimer = new DispatcherTimer(TimeSpan.FromMilliseconds(40), DispatcherPriority.Background, (_, _) => Update());
HostScreen = hostScreen; DisplayName = "Data Model";
Modules = new ObservableCollection<Module>(); Modules = new ObservableCollection<Module>();
this.WhenActivated(disposables => this.WhenActivated(disposables =>
{ {
Observable.FromEventPattern<PluginFeatureEventArgs>(x => pluginManagementService.PluginFeatureEnabled += x, x => pluginManagementService.PluginFeatureEnabled -= x) Observable.FromEventPattern<PluginFeatureEventArgs>(x => pluginManagementService.PluginFeatureEnabled += x, x => pluginManagementService.PluginFeatureEnabled -= x)
@ -142,7 +142,4 @@ public class DataModelDebugViewModel : ActivatableViewModelBase, IRoutableViewMo
SelectedModule = null; SelectedModule = null;
} }
} }
public string UrlPathSegment => "data-model";
public IScreen HostScreen { get; }
} }

View File

@ -10,7 +10,7 @@
On this page you can view Artemis's logs in real-time. Logging can come from Artemis itself, plugins and scripts. On this page you can view Artemis's logs in real-time. Logging can come from Artemis itself, plugins and scripts.
</TextBlock> </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 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> <TextBlock Classes="subtitle">#feelsbadman</TextBlock>
</StackPanel> </StackPanel>
</UserControl> </UserControl>

View File

@ -1,18 +1,17 @@
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI; using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.Debugger.Logs namespace Artemis.UI.Screens.Debugger.Logs;
{
public class LogsDebugView : ReactiveUserControl<LogsDebugViewModel>
{
public LogsDebugView()
{
InitializeComponent();
}
private void InitializeComponent() public class LogsDebugView : ReactiveUserControl<LogsDebugViewModel>
{ {
AvaloniaXamlLoader.Load(this); public LogsDebugView()
} {
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
} }
} }

View File

@ -1,16 +1,11 @@
using Artemis.UI.Shared; using Artemis.UI.Shared;
using ReactiveUI;
namespace Artemis.UI.Screens.Debugger.Logs namespace Artemis.UI.Screens.Debugger.Logs;
public class LogsDebugViewModel : ActivatableViewModelBase
{ {
public class LogsDebugViewModel : ActivatableViewModelBase, IRoutableViewModel public LogsDebugViewModel()
{ {
public LogsDebugViewModel(IScreen hostScreen) DisplayName = "Logs";
{
HostScreen = hostScreen;
}
public string UrlPathSegment => "logs";
public IScreen HostScreen { get; }
} }
} }

View File

@ -1,61 +1,59 @@
using Artemis.Core; using Artemis.Core;
using Artemis.UI.Shared; using Artemis.UI.Shared;
using ReactiveUI;
namespace Artemis.UI.Screens.Debugger.Performance namespace Artemis.UI.Screens.Debugger.Performance;
public class PerformanceDebugMeasurementViewModel : ViewModelBase
{ {
public class PerformanceDebugMeasurementViewModel : ViewModelBase private string? _average;
private string? _last;
private string? _max;
private string? _min;
private string? _percentile;
public PerformanceDebugMeasurementViewModel(ProfilingMeasurement measurement)
{ {
private string? _average; Measurement = measurement;
private string? _last; }
private string? _max;
private string? _min;
private string? _percentile;
public PerformanceDebugMeasurementViewModel(ProfilingMeasurement measurement) public ProfilingMeasurement Measurement { get; }
{
Measurement = measurement;
}
public ProfilingMeasurement Measurement { get; } public string? Last
{
get => _last;
set => RaiseAndSetIfChanged(ref _last, value);
}
public string? Last public string? Average
{ {
get => _last; get => _average;
set => RaiseAndSetIfChanged(ref _last, value); set => RaiseAndSetIfChanged(ref _average, value);
} }
public string? Average public string? Min
{ {
get => _average; get => _min;
set => RaiseAndSetIfChanged(ref _average, value); set => RaiseAndSetIfChanged(ref _min, value);
} }
public string? Min public string? Max
{ {
get => _min; get => _max;
set => RaiseAndSetIfChanged(ref _min, value); set => RaiseAndSetIfChanged(ref _max, value);
} }
public string? Max public string? Percentile
{ {
get => _max; get => _percentile;
set => RaiseAndSetIfChanged(ref _max, value); set => RaiseAndSetIfChanged(ref _percentile, value);
} }
public string? Percentile public void Update()
{ {
get => _percentile; Last = Measurement.GetLast().TotalMilliseconds + " ms";
set => RaiseAndSetIfChanged(ref _percentile, value); Average = Measurement.GetAverage().TotalMilliseconds + " ms";
} Min = Measurement.GetMin().TotalMilliseconds + " ms";
Max = Measurement.GetMax().TotalMilliseconds + " ms";
public void Update() Percentile = Measurement.GetPercentile(0.95).TotalMilliseconds + " ms";
{
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";
}
} }
} }

View File

@ -5,14 +5,14 @@
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared" xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Artemis.UI.Screens.Debugger.Performance.PerformanceDebugPluginView"> x:Class="Artemis.UI.Screens.Debugger.Performance.PerformanceDebugPluginView">
<Border Classes="card-condensed" Margin="0 5"> <Border Classes="card-condensed" Margin="0 5">
<StackPanel> <StackPanel>
<Grid ColumnDefinitions="40,*"> <Grid ColumnDefinitions="40,*">
<shared:ArtemisIcon Grid.Column="0" Icon="{Binding Plugin.Info.ResolvedIcon}" Width="24" Height="24" /> <shared: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}" /> <TextBlock Grid.Column="1" VerticalAlignment="Center" Classes="h5" Text="{Binding Plugin.Info.Name}" />
</Grid> </Grid>
<ItemsControl Items="{Binding Profilers}"/> <ItemsControl Items="{Binding Profilers}" />
</StackPanel> </StackPanel>
</Border> </Border>
</UserControl> </UserControl>

View File

@ -1,18 +1,17 @@
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
namespace Artemis.UI.Screens.Debugger.Performance namespace Artemis.UI.Screens.Debugger.Performance;
{
public partial class PerformanceDebugPluginView : UserControl
{
public PerformanceDebugPluginView()
{
InitializeComponent();
}
private void InitializeComponent() public class PerformanceDebugPluginView : UserControl
{ {
AvaloniaXamlLoader.Load(this); public PerformanceDebugPluginView()
} {
InitializeComponent();
} }
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}

View File

@ -3,29 +3,28 @@ using System.Linq;
using Artemis.Core; using Artemis.Core;
using Artemis.UI.Shared; using Artemis.UI.Shared;
namespace Artemis.UI.Screens.Debugger.Performance namespace Artemis.UI.Screens.Debugger.Performance;
public class PerformanceDebugPluginViewModel : ViewModelBase
{ {
public class PerformanceDebugPluginViewModel : ViewModelBase public PerformanceDebugPluginViewModel(Plugin plugin)
{ {
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()))
{ {
Plugin = plugin; if (Profilers.All(p => p.Profiler != pluginProfiler))
Profilers.Add(new PerformanceDebugProfilerViewModel(pluginProfiler));
} }
public Plugin Plugin { get; } foreach (PerformanceDebugProfilerViewModel profilerViewModel in Profilers)
profilerViewModel.Update();
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();
}
} }
} }

View File

@ -14,7 +14,7 @@
IsReadOnly="True" IsReadOnly="True"
AutoGenerateColumns="False" AutoGenerateColumns="False"
CanUserReorderColumns="False" CanUserReorderColumns="False"
CanUserResizeColumns="False" CanUserResizeColumns="False"
Margin="10 5 10 10"> Margin="10 5 10 10">
<DataGrid.Columns> <DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Measurement.Identifier}" Header="Identifier" /> <DataGridTextColumn Binding="{Binding Measurement.Identifier}" Header="Identifier" />
@ -26,4 +26,4 @@
</DataGrid.Columns> </DataGrid.Columns>
</DataGrid> </DataGrid>
</StackPanel> </StackPanel>
</UserControl> </UserControl>

View File

@ -1,18 +1,17 @@
using Avalonia.Controls; using Avalonia.Controls;
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
namespace Artemis.UI.Screens.Debugger.Performance namespace Artemis.UI.Screens.Debugger.Performance;
{
public partial class PerformanceDebugProfilerView : UserControl
{
public PerformanceDebugProfilerView()
{
InitializeComponent();
}
private void InitializeComponent() public class PerformanceDebugProfilerView : UserControl
{ {
AvaloniaXamlLoader.Load(this); public PerformanceDebugProfilerView()
} {
InitializeComponent();
} }
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
}

View File

@ -3,29 +3,28 @@ using System.Linq;
using Artemis.Core; using Artemis.Core;
using Artemis.UI.Shared; using Artemis.UI.Shared;
namespace Artemis.UI.Screens.Debugger.Performance namespace Artemis.UI.Screens.Debugger.Performance;
public class PerformanceDebugProfilerViewModel : ViewModelBase
{ {
public class PerformanceDebugProfilerViewModel : ViewModelBase public PerformanceDebugProfilerViewModel(Profiler profiler)
{ {
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)
{ {
Profiler = profiler; if (Measurements.All(m => m.Measurement != measurement))
Measurements.Add(new PerformanceDebugMeasurementViewModel(measurement));
} }
public Profiler Profiler { get; } foreach (PerformanceDebugMeasurementViewModel profilingMeasurementViewModel in Measurements)
profilingMeasurementViewModel.Update();
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();
}
} }
} }

View File

@ -28,12 +28,12 @@
<TextBlock Text="{Binding RenderWidth}" /> <TextBlock Text="{Binding RenderWidth}" />
<TextBlock Text="x" /> <TextBlock Text="x" />
<TextBlock Text="{Binding RenderHeight}" /> <TextBlock Text="{Binding RenderHeight}" />
<TextBlock Text=" - Renderer: "></TextBlock> <TextBlock Text=" - Renderer: " />
<TextBlock Text="{Binding Renderer}"></TextBlock> <TextBlock Text="{Binding Renderer}" />
</StackPanel> </StackPanel>
<ScrollViewer Grid.Row="2" VerticalScrollBarVisibility="Auto"> <ScrollViewer Grid.Row="2" VerticalScrollBarVisibility="Auto">
<ItemsControl Items="{Binding Items}" Margin="0 0 10 0" /> <ItemsControl Items="{Binding Items}" Margin="0 0 10 0" />
</ScrollViewer> </ScrollViewer>
</Grid> </Grid>

View File

@ -1,18 +1,17 @@
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI; using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.Debugger.Performance namespace Artemis.UI.Screens.Debugger.Performance;
{
public class PerformanceDebugView : ReactiveUserControl<PerformanceDebugViewModel>
{
public PerformanceDebugView()
{
InitializeComponent();
}
private void InitializeComponent() public class PerformanceDebugView : ReactiveUserControl<PerformanceDebugViewModel>
{ {
AvaloniaXamlLoader.Load(this); public PerformanceDebugView()
} {
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
} }
} }

View File

@ -12,7 +12,7 @@ using SkiaSharp;
namespace Artemis.UI.Screens.Debugger.Performance; namespace Artemis.UI.Screens.Debugger.Performance;
public class PerformanceDebugViewModel : ActivatableViewModelBase, IRoutableViewModel public class PerformanceDebugViewModel : ActivatableViewModelBase
{ {
private readonly ICoreService _coreService; private readonly ICoreService _coreService;
private readonly IPluginManagementService _pluginManagementService; private readonly IPluginManagementService _pluginManagementService;
@ -22,13 +22,14 @@ public class PerformanceDebugViewModel : ActivatableViewModelBase, IRoutableView
private int _renderHeight; private int _renderHeight;
private int _renderWidth; private int _renderWidth;
public PerformanceDebugViewModel(IScreen hostScreen, ICoreService coreService, IPluginManagementService pluginManagementService) public PerformanceDebugViewModel(ICoreService coreService, IPluginManagementService pluginManagementService)
{ {
HostScreen = hostScreen;
_coreService = coreService; _coreService = coreService;
_pluginManagementService = pluginManagementService; _pluginManagementService = pluginManagementService;
_updateTimer = new DispatcherTimer(TimeSpan.FromMilliseconds(500), DispatcherPriority.Normal, (_, _) => Update()); _updateTimer = new DispatcherTimer(TimeSpan.FromMilliseconds(500), DispatcherPriority.Normal, (_, _) => Update());
DisplayName = "Performance";
this.WhenActivated(disposables => this.WhenActivated(disposables =>
{ {
Observable.FromEventPattern<PluginFeatureEventArgs>(x => pluginManagementService.PluginFeatureEnabled += x, x => pluginManagementService.PluginFeatureEnabled -= x) Observable.FromEventPattern<PluginFeatureEventArgs>(x => pluginManagementService.PluginFeatureEnabled += x, x => pluginManagementService.PluginFeatureEnabled -= x)
@ -123,8 +124,4 @@ public class PerformanceDebugViewModel : ActivatableViewModelBase, IRoutableView
RenderHeight = bitmapInfo.Height; RenderHeight = bitmapInfo.Height;
RenderWidth = bitmapInfo.Width; RenderWidth = bitmapInfo.Width;
} }
public string UrlPathSegment => "performance";
public IScreen HostScreen { get; }
} }

View File

@ -20,25 +20,25 @@
<TextBlock Text="{Binding RenderWidth}" /> <TextBlock Text="{Binding RenderWidth}" />
<TextBlock Text="x" /> <TextBlock Text="x" />
<TextBlock Text="{Binding RenderHeight}" /> <TextBlock Text="{Binding RenderHeight}" />
<TextBlock Text=" - Renderer: "></TextBlock> <TextBlock Text=" - Renderer: " />
<TextBlock Text="{Binding Renderer}"></TextBlock> <TextBlock Text="{Binding Renderer}" />
</StackPanel> </StackPanel>
<Border Classes="card" Padding="10"> <Border Classes="card" Padding="10">
<ZoomBorder Name="ZoomBorder" <ZoomBorder Name="ZoomBorder"
Stretch="None" Stretch="None"
ClipToBounds="True" ClipToBounds="True"
Focusable="True" Focusable="True"
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
HorizontalAlignment="Stretch"> HorizontalAlignment="Stretch">
<Image Name="Visualization" Source="{Binding CurrentFrame}"> <Image Name="Visualization" Source="{Binding CurrentFrame}">
<Image.Transitions> <Image.Transitions>
<Transitions> <Transitions>
<TransformOperationsTransition Property="RenderTransform" Duration="0:0:0.2" Easing="CubicEaseOut"/> <TransformOperationsTransition Property="RenderTransform" Duration="0:0:0.2" Easing="CubicEaseOut" />
</Transitions> </Transitions>
</Image.Transitions> </Image.Transitions>
</Image> </Image>
</ZoomBorder> </ZoomBorder>
</Border> </Border>
</StackPanel> </StackPanel>
</UserControl> </UserControl>

View File

@ -1,18 +1,17 @@
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI; using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.Debugger.Render namespace Artemis.UI.Screens.Debugger.Render;
{
public class RenderDebugView : ReactiveUserControl<RenderDebugViewModel>
{
public RenderDebugView()
{
InitializeComponent();
}
private void InitializeComponent() public class RenderDebugView : ReactiveUserControl<RenderDebugViewModel>
{ {
AvaloniaXamlLoader.Load(this); public RenderDebugView()
} {
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
} }
} }

View File

@ -7,102 +7,99 @@ using Avalonia.Media.Imaging;
using ReactiveUI; using ReactiveUI;
using SkiaSharp; using SkiaSharp;
namespace Artemis.UI.Screens.Debugger.Render namespace Artemis.UI.Screens.Debugger.Render;
public class RenderDebugViewModel : ActivatableViewModelBase
{ {
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(ICoreService coreService)
{ {
private readonly ICoreService _coreService; _coreService = coreService;
private double _currentFps;
private Bitmap? _currentFrame; DisplayName = "Rendering";
private string? _frameTargetPath;
private string? _renderer;
private int _renderHeight;
private int _renderWidth;
public RenderDebugViewModel(DebugViewModel hostScreen, ICoreService coreService) this.WhenActivated(disposables =>
{ {
HostScreen = hostScreen; HandleActivation();
_coreService = coreService; Disposable.Create(HandleDeactivation).DisposeWith(disposables);
});
}
this.WhenActivated(disposables => public Bitmap? CurrentFrame
{ {
HandleActivation(); get => _currentFrame;
Disposable.Create(HandleDeactivation).DisposeWith(disposables); set => RaiseAndSetIfChanged(ref _currentFrame, value);
}); }
}
public Bitmap? CurrentFrame 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)
{ {
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)) using (SKData data = skImage.Encode(SKEncodedImageFormat.Png, 100))
{ {
CurrentFrame = new Bitmap(data.AsStream()); using (FileStream stream = File.OpenWrite(_frameTargetPath))
{
data.SaveTo(stream);
}
} }
_frameTargetPath = null;
} }
public string UrlPathSegment => "render"; RenderHeight = bitmapInfo.Height;
public IScreen HostScreen { get; } 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());
}
} }
} }

View File

@ -1,18 +1,17 @@
using Avalonia.Markup.Xaml; using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI; using Avalonia.ReactiveUI;
namespace Artemis.UI.Screens.Debugger.Settings namespace Artemis.UI.Screens.Debugger.Settings;
{
public class DebugSettingsView : ReactiveUserControl<DebugSettingsViewModel>
{
public DebugSettingsView()
{
InitializeComponent();
}
private void InitializeComponent() public class DebugSettingsView : ReactiveUserControl<DebugSettingsViewModel>
{ {
AvaloniaXamlLoader.Load(this); public DebugSettingsView()
} {
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
} }
} }

View File

@ -1,16 +1,11 @@
using Artemis.UI.Shared; using Artemis.UI.Shared;
using ReactiveUI;
namespace Artemis.UI.Screens.Debugger.Settings namespace Artemis.UI.Screens.Debugger.Settings;
public class DebugSettingsViewModel : ActivatableViewModelBase
{ {
public class DebugSettingsViewModel : ActivatableViewModelBase, IRoutableViewModel public DebugSettingsViewModel()
{ {
public DebugSettingsViewModel(IScreen hostScreen) DisplayName = "Settings";
{
HostScreen = hostScreen;
}
public string UrlPathSegment => "logs";
public IScreen HostScreen { get; }
} }
} }

View File

@ -17,22 +17,18 @@
<TextBox Classes="clearButton" Text="{CompiledBinding SearchPluginInput}" Watermark="Search plugins" Margin="0 0 10 0" /> <TextBox Classes="clearButton" Text="{CompiledBinding SearchPluginInput}" Watermark="Search plugins" Margin="0 0 10 0" />
<StackPanel Spacing="5" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Right" Orientation="Horizontal"> <StackPanel Spacing="5" Grid.Row="0" Grid.Column="1" HorizontalAlignment="Right" Orientation="Horizontal">
<controls:HyperlinkButton Grid.Row="0" <controls:HyperlinkButton VerticalAlignment="Top" NavigateUri="https://wiki.artemis-rgb.com/en/guides/user/plugins">
Grid.Column="1"
VerticalAlignment="Top"
NavigateUri="https://wiki.artemis-rgb.com/en/guides/user/plugins">
Get more plugins Get more plugins
</controls:HyperlinkButton> </controls:HyperlinkButton>
<Button Classes="accent" Command="{CompiledBinding ImportPlugin}">Import plugin</Button> <Button Classes="accent" Command="{CompiledBinding ImportPlugin}">Import plugin</Button>
</StackPanel> </StackPanel>
</Grid> </Grid>
<ScrollViewer Grid.Row="1" Grid.Column="0" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" VerticalAlignment="Top"> <ScrollViewer Grid.Row="1" Grid.Column="0" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto" VerticalAlignment="Top">
<ItemsRepeater Items="{CompiledBinding Plugins}" MaxWidth="900" VerticalAlignment="Center"> <ItemsRepeater Items="{CompiledBinding Plugins}" MaxWidth="900" VerticalAlignment="Center">
<ItemsRepeater.ItemTemplate> <ItemsRepeater.ItemTemplate>
<DataTemplate x:DataType="plugins:PluginSettingsViewModel"> <DataTemplate x:DataType="plugins:PluginSettingsViewModel">
<ContentControl Content="{CompiledBinding}"/> <ContentControl Content="{CompiledBinding}" Height="200"/>
</DataTemplate> </DataTemplate>
</ItemsRepeater.ItemTemplate> </ItemsRepeater.ItemTemplate>
</ItemsRepeater> </ItemsRepeater>

View File

@ -36,12 +36,13 @@ namespace Artemis.UI.Screens.Settings
DisplayName = "Plugins"; DisplayName = "Plugins";
SourceList<Plugin> plugins = new(); SourceList<Plugin> plugins = new();
IObservable<Func<Plugin, bool>> pluginFilter = this.WhenAnyValue(vm => vm.SearchPluginInput).Throttle(TimeSpan.FromMilliseconds(100), AvaloniaScheduler.Instance).Select(CreatePredicate); IObservable<Func<Plugin, bool>> pluginFilter = this.WhenAnyValue(vm => vm.SearchPluginInput).Throttle(TimeSpan.FromMilliseconds(100)).Select(CreatePredicate);
plugins.Connect() plugins.Connect()
.Filter(pluginFilter) .Filter(pluginFilter)
.Sort(SortExpressionComparer<Plugin>.Ascending(p => p.Info.Name)) .Sort(SortExpressionComparer<Plugin>.Ascending(p => p.Info.Name))
.Transform(settingsVmFactory.PluginSettingsViewModel) .Transform(settingsVmFactory.PluginSettingsViewModel)
.ObserveOn(AvaloniaScheduler.Instance)
.Bind(out ReadOnlyObservableCollection<PluginSettingsViewModel> pluginViewModels) .Bind(out ReadOnlyObservableCollection<PluginSettingsViewModel> pluginViewModels)
.Subscribe(); .Subscribe();
Plugins = pluginViewModels; Plugins = pluginViewModels;

View File

@ -47,36 +47,42 @@ Global
{035CBB38-7B9E-4375-A39C-E9A5B01F23A5}.Release|Any CPU.ActiveCfg = Release|x64 {035CBB38-7B9E-4375-A39C-E9A5B01F23A5}.Release|Any CPU.ActiveCfg = Release|x64
{035CBB38-7B9E-4375-A39C-E9A5B01F23A5}.Release|x64.ActiveCfg = Release|x64 {035CBB38-7B9E-4375-A39C-E9A5B01F23A5}.Release|x64.ActiveCfg = Release|x64
{035CBB38-7B9E-4375-A39C-E9A5B01F23A5}.Debug|Any CPU.Build.0 = Debug|x64 {035CBB38-7B9E-4375-A39C-E9A5B01F23A5}.Debug|Any CPU.Build.0 = Debug|x64
{035CBB38-7B9E-4375-A39C-E9A5B01F23A5}.Release|x64.Build.0 = Release|x64
{05A5AB0F-A303-4404-9623-4DB1C9AA1DA0}.Debug|Any CPU.ActiveCfg = Debug|x64 {05A5AB0F-A303-4404-9623-4DB1C9AA1DA0}.Debug|Any CPU.ActiveCfg = Debug|x64
{05A5AB0F-A303-4404-9623-4DB1C9AA1DA0}.Debug|x64.ActiveCfg = Debug|x64 {05A5AB0F-A303-4404-9623-4DB1C9AA1DA0}.Debug|x64.ActiveCfg = Debug|x64
{05A5AB0F-A303-4404-9623-4DB1C9AA1DA0}.Debug|x64.Build.0 = Debug|x64 {05A5AB0F-A303-4404-9623-4DB1C9AA1DA0}.Debug|x64.Build.0 = Debug|x64
{05A5AB0F-A303-4404-9623-4DB1C9AA1DA0}.Release|Any CPU.ActiveCfg = Release|x64 {05A5AB0F-A303-4404-9623-4DB1C9AA1DA0}.Release|Any CPU.ActiveCfg = Release|x64
{05A5AB0F-A303-4404-9623-4DB1C9AA1DA0}.Release|x64.ActiveCfg = Release|x64 {05A5AB0F-A303-4404-9623-4DB1C9AA1DA0}.Release|x64.ActiveCfg = Release|x64
{05A5AB0F-A303-4404-9623-4DB1C9AA1DA0}.Debug|Any CPU.Build.0 = Debug|x64 {05A5AB0F-A303-4404-9623-4DB1C9AA1DA0}.Debug|Any CPU.Build.0 = Debug|x64
{05A5AB0F-A303-4404-9623-4DB1C9AA1DA0}.Release|x64.Build.0 = Release|x64
{DE45A288-9320-461F-BE2A-26DFE3817216}.Debug|Any CPU.ActiveCfg = Debug|x64 {DE45A288-9320-461F-BE2A-26DFE3817216}.Debug|Any CPU.ActiveCfg = Debug|x64
{DE45A288-9320-461F-BE2A-26DFE3817216}.Debug|x64.ActiveCfg = Debug|x64 {DE45A288-9320-461F-BE2A-26DFE3817216}.Debug|x64.ActiveCfg = Debug|x64
{DE45A288-9320-461F-BE2A-26DFE3817216}.Debug|x64.Build.0 = Debug|x64 {DE45A288-9320-461F-BE2A-26DFE3817216}.Debug|x64.Build.0 = Debug|x64
{DE45A288-9320-461F-BE2A-26DFE3817216}.Release|Any CPU.ActiveCfg = Release|x64 {DE45A288-9320-461F-BE2A-26DFE3817216}.Release|Any CPU.ActiveCfg = Release|x64
{DE45A288-9320-461F-BE2A-26DFE3817216}.Release|x64.ActiveCfg = Release|x64 {DE45A288-9320-461F-BE2A-26DFE3817216}.Release|x64.ActiveCfg = Release|x64
{DE45A288-9320-461F-BE2A-26DFE3817216}.Debug|Any CPU.Build.0 = Debug|x64 {DE45A288-9320-461F-BE2A-26DFE3817216}.Debug|Any CPU.Build.0 = Debug|x64
{DE45A288-9320-461F-BE2A-26DFE3817216}.Release|x64.Build.0 = Release|x64
{9012C8E2-3BEC-42F5-8270-7352A5922B04}.Debug|Any CPU.ActiveCfg = Debug|x64 {9012C8E2-3BEC-42F5-8270-7352A5922B04}.Debug|Any CPU.ActiveCfg = Debug|x64
{9012C8E2-3BEC-42F5-8270-7352A5922B04}.Debug|x64.ActiveCfg = Debug|x64 {9012C8E2-3BEC-42F5-8270-7352A5922B04}.Debug|x64.ActiveCfg = Debug|x64
{9012C8E2-3BEC-42F5-8270-7352A5922B04}.Debug|x64.Build.0 = Debug|x64 {9012C8E2-3BEC-42F5-8270-7352A5922B04}.Debug|x64.Build.0 = Debug|x64
{9012C8E2-3BEC-42F5-8270-7352A5922B04}.Release|Any CPU.ActiveCfg = Release|x64 {9012C8E2-3BEC-42F5-8270-7352A5922B04}.Release|Any CPU.ActiveCfg = Release|x64
{9012C8E2-3BEC-42F5-8270-7352A5922B04}.Release|x64.ActiveCfg = Release|x64 {9012C8E2-3BEC-42F5-8270-7352A5922B04}.Release|x64.ActiveCfg = Release|x64
{9012C8E2-3BEC-42F5-8270-7352A5922B04}.Debug|Any CPU.Build.0 = Debug|x64 {9012C8E2-3BEC-42F5-8270-7352A5922B04}.Debug|Any CPU.Build.0 = Debug|x64
{9012C8E2-3BEC-42F5-8270-7352A5922B04}.Release|x64.Build.0 = Release|x64
{2F5F16DC-FACF-4559-9882-37C2949814C7}.Debug|Any CPU.ActiveCfg = Debug|x64 {2F5F16DC-FACF-4559-9882-37C2949814C7}.Debug|Any CPU.ActiveCfg = Debug|x64
{2F5F16DC-FACF-4559-9882-37C2949814C7}.Debug|x64.ActiveCfg = Debug|x64 {2F5F16DC-FACF-4559-9882-37C2949814C7}.Debug|x64.ActiveCfg = Debug|x64
{2F5F16DC-FACF-4559-9882-37C2949814C7}.Debug|x64.Build.0 = Debug|x64 {2F5F16DC-FACF-4559-9882-37C2949814C7}.Debug|x64.Build.0 = Debug|x64
{2F5F16DC-FACF-4559-9882-37C2949814C7}.Release|Any CPU.ActiveCfg = Release|x64 {2F5F16DC-FACF-4559-9882-37C2949814C7}.Release|Any CPU.ActiveCfg = Release|x64
{2F5F16DC-FACF-4559-9882-37C2949814C7}.Release|x64.ActiveCfg = Release|x64 {2F5F16DC-FACF-4559-9882-37C2949814C7}.Release|x64.ActiveCfg = Release|x64
{2F5F16DC-FACF-4559-9882-37C2949814C7}.Debug|Any CPU.Build.0 = Debug|x64 {2F5F16DC-FACF-4559-9882-37C2949814C7}.Debug|Any CPU.Build.0 = Debug|x64
{2F5F16DC-FACF-4559-9882-37C2949814C7}.Release|x64.Build.0 = Release|x64
{412B921A-26F5-4AE6-8B32-0C19BE54F421}.Debug|Any CPU.ActiveCfg = Debug|x64 {412B921A-26F5-4AE6-8B32-0C19BE54F421}.Debug|Any CPU.ActiveCfg = Debug|x64
{412B921A-26F5-4AE6-8B32-0C19BE54F421}.Debug|x64.ActiveCfg = Debug|x64 {412B921A-26F5-4AE6-8B32-0C19BE54F421}.Debug|x64.ActiveCfg = Debug|x64
{412B921A-26F5-4AE6-8B32-0C19BE54F421}.Debug|x64.Build.0 = Debug|x64 {412B921A-26F5-4AE6-8B32-0C19BE54F421}.Debug|x64.Build.0 = Debug|x64
{412B921A-26F5-4AE6-8B32-0C19BE54F421}.Release|Any CPU.ActiveCfg = Release|x64 {412B921A-26F5-4AE6-8B32-0C19BE54F421}.Release|Any CPU.ActiveCfg = Release|x64
{412B921A-26F5-4AE6-8B32-0C19BE54F421}.Release|x64.ActiveCfg = Release|x64 {412B921A-26F5-4AE6-8B32-0C19BE54F421}.Release|x64.ActiveCfg = Release|x64
{412B921A-26F5-4AE6-8B32-0C19BE54F421}.Debug|Any CPU.Build.0 = Debug|x64 {412B921A-26F5-4AE6-8B32-0C19BE54F421}.Debug|Any CPU.Build.0 = Debug|x64
{412B921A-26F5-4AE6-8B32-0C19BE54F421}.Release|x64.Build.0 = Release|x64
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE