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

UI - Settings General tab

This commit is contained in:
Robert 2021-10-19 21:32:21 +02:00
parent 491a0bdbc3
commit 6bbe6b6bbe
27 changed files with 831 additions and 21 deletions

View File

@ -33,7 +33,6 @@ namespace Artemis.Core
/// <typeparam name="T">The type of the setting, can be any serializable type</typeparam>
/// <param name="name">The name of the setting</param>
/// <param name="defaultValue">The default value to use if the setting does not exist yet</param>
/// <returns></returns>
public PluginSetting<T> GetSetting<T>(string name, T? defaultValue = default)
{
lock (_settingEntities)

View File

@ -0,0 +1,36 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Humanizer;
namespace Artemis.Core
{
/// <summary>
/// Provides utilities for display enums in a human readable form
/// </summary>
public static class EnumUtilities
{
/// <summary>
/// Creates a list containing a tuple for each value in the enum type
/// </summary>
/// <param name="t">The enum type to create value descriptions for</param>
/// <returns>A list containing a value-description tuple for each value in the enum type</returns>
public static List<(T, string)> GetAllValuesAndDescriptions<T>() where T : struct, Enum
{
return Enum.GetValues<T>().Select(e => (e, e.Humanize())).ToList();
}
/// <summary>
/// Creates a list containing a tuple for each value in the enum type
/// </summary>
/// <param name="t">The enum type to create value descriptions for</param>
/// <returns>A list containing a value-description tuple for each value in the enum type</returns>
public static List<(Enum, string)> GetAllValuesAndDescriptions(Type t)
{
if (!t.IsEnum)
throw new ArgumentException($"{t} must be an enum type");
return Enum.GetValues(t).Cast<Enum>().Select(e => (e, e.Humanize())).ToList();
}
}
}

View File

@ -142,7 +142,7 @@ namespace Artemis.UI.Avalonia.Shared.Controls
/// Gets or sets the <see cref="ArtemisDevice" /> to display
/// </summary>
public static readonly StyledProperty<ArtemisDevice?> DeviceProperty =
AvaloniaProperty.Register<ProfileConfigurationIcon, ArtemisDevice?>(nameof(Device));
AvaloniaProperty.Register<DeviceVisualizer, ArtemisDevice?>(nameof(Device));
/// <summary>
/// Gets or sets the <see cref="ArtemisDevice" /> to display
@ -157,7 +157,7 @@ namespace Artemis.UI.Avalonia.Shared.Controls
/// Gets or sets boolean indicating whether or not to show per-LED colors
/// </summary>
public static readonly StyledProperty<bool> ShowColorsProperty =
AvaloniaProperty.Register<ProfileConfigurationIcon, bool>(nameof(ShowColors));
AvaloniaProperty.Register<DeviceVisualizer, bool>(nameof(ShowColors));
/// <summary>
/// Gets or sets a boolean indicating whether or not to show per-LED colors
@ -172,7 +172,7 @@ namespace Artemis.UI.Avalonia.Shared.Controls
/// Gets or sets a list of LEDs to highlight
/// </summary>
public static readonly StyledProperty<ObservableCollection<ArtemisLed>?> HighlightedLedsProperty =
AvaloniaProperty.Register<ProfileConfigurationIcon, ObservableCollection<ArtemisLed>?>(nameof(HighlightedLeds));
AvaloniaProperty.Register<DeviceVisualizer, ObservableCollection<ArtemisLed>?>(nameof(HighlightedLeds));
/// <summary>
/// Gets or sets a list of LEDs to highlight

View File

@ -0,0 +1,14 @@
<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.Avalonia.Shared.Controls.EnumComboBox">
<ComboBox x:Name="EnumComboBox" HorizontalAlignment="Stretch">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding [0]}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</UserControl>

View File

@ -0,0 +1,109 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using Artemis.Core;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.LogicalTree;
using Avalonia.Markup.Xaml;
namespace Artemis.UI.Avalonia.Shared.Controls
{
public partial class EnumComboBox : UserControl
{
/// <summary>
/// Gets or sets the currently selected value
/// </summary>
public static readonly StyledProperty<object?> ValueProperty =
AvaloniaProperty.Register<EnumComboBox, object?>(nameof(Value), defaultBindingMode: BindingMode.TwoWay, notifying: ValueChanged);
/// <summary>
/// Gets or sets the currently selected value
/// </summary>
public object? Value
{
get => GetValue(ValueProperty);
set => SetValue(ValueProperty, value);
}
private ComboBox? _enumComboBox;
private readonly ObservableCollection<(Enum, string)> _currentValues = new();
private static void ValueChanged(IAvaloniaObject sender, bool before)
{
if (sender is EnumComboBox enumCombo && !before)
{
enumCombo.UpdateValues();
enumCombo.UpdateSelection();
}
}
public EnumComboBox()
{
InitializeComponent();
}
private void InitializeComponent()
{
AvaloniaXamlLoader.Load(this);
}
private void OnSelectionChanged(object? sender, SelectionChangedEventArgs e)
{
if (_enumComboBox == null)
return;
var (enumValue, _) = _currentValues[_enumComboBox.SelectedIndex];
if (!Equals(Value, enumValue))
Value = enumValue;
}
private void UpdateValues()
{
Type? newType = Value?.GetType();
if (_enumComboBox == null || _currentValues.Any() || newType is not {IsEnum: true})
return;
foreach ((Enum, string) valueDesc in EnumUtilities.GetAllValuesAndDescriptions(newType))
_currentValues.Add(valueDesc);
}
private void UpdateSelection()
{
if (_enumComboBox == null || Value is not Enum)
return;
(Enum, string) value = _currentValues.FirstOrDefault(v => v.Item1.Equals(Value));
if (!Equals(value.Item1, _enumComboBox.SelectedItem))
_enumComboBox.SelectedItem = value;
}
#region Overrides of TemplatedControl
/// <inheritdoc />
protected override void OnAttachedToLogicalTree(LogicalTreeAttachmentEventArgs e)
{
_enumComboBox = this.Get<ComboBox>("EnumComboBox");
_enumComboBox.Items = _currentValues;
UpdateValues();
UpdateSelection();
_enumComboBox.SelectionChanged += OnSelectionChanged;
base.OnAttachedToLogicalTree(e);
}
/// <inheritdoc />
protected override void OnDetachedFromLogicalTree(LogicalTreeAttachmentEventArgs e)
{
if (_enumComboBox != null)
_enumComboBox.SelectionChanged -= OnSelectionChanged;
base.OnDetachedFromLogicalTree(e);
}
#endregion
}
}

View File

@ -0,0 +1,9 @@
namespace Artemis.UI.Avalonia.Shared.Services.Interfaces
{
/// <summary>
/// Represents a service provided by the Artemis Shared UI library
/// </summary>
public interface IArtemisSharedUIService
{
}
}

View File

@ -4,8 +4,10 @@ using Artemis.UI.Avalonia.Screens.Root.ViewModels;
using Avalonia;
using Avalonia.Controls.ApplicationLifetimes;
using Avalonia.Markup.Xaml;
using Avalonia.Threading;
using FluentAvalonia.Styling;
using Ninject;
using ReactiveUI;
using Splat.Ninject;
namespace Artemis.UI.Avalonia
@ -17,6 +19,8 @@ namespace Artemis.UI.Avalonia
public override void Initialize()
{
InitializeNinject();
RxApp.MainThreadScheduler = AvaloniaScheduler.Instance;
AvaloniaXamlLoader.Load(this);
}

View File

@ -0,0 +1,76 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net5.0</TargetFramework>
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Folder Include="Controls\" />
<Folder Include="Models\" />
<AvaloniaResource Include="Assets\**" />
</ItemGroup>
<ItemGroup>
<None Remove="Assets\Images\home-banner.png" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="Avalonia" Version="0.10.7" />
<PackageReference Include="Avalonia.Desktop" Version="0.10.7" />
<PackageReference Include="Avalonia.Diagnostics" Version="0.10.7" />
<PackageReference Include="Avalonia.ReactiveUI" Version="0.10.7" />
<PackageReference Include="Avalonia.Svg.Skia" Version="0.10.7.2" />
<PackageReference Include="FluentAvaloniaUI" Version="1.1.3" />
<PackageReference Include="Flurl.Http" Version="3.2.0" />
<PackageReference Include="Live.Avalonia" Version="1.3.1" />
<PackageReference Include="Material.Icons.Avalonia" Version="1.0.2" />
<PackageReference Include="Splat.Ninject" Version="13.1.22" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Artemis.Core\Artemis.Core.csproj" />
<ProjectReference Include="..\Artemis.UI.Avalonia.Shared\Artemis.UI.Avalonia.Shared.csproj" />
</ItemGroup>
<ItemGroup>
<Compile Update="MainWindow.axaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<Compile Update="Screens\Root\Views\SidebarCategoryView.axaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<Compile Update="Screens\Root\Views\SidebarProfileConfigurationView.axaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<Compile Update="Screens\Root\Views\SidebarScreenView.axaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<Compile Update="Screens\Root\Views\SidebarView.axaml.cs">
<DependentUpon>%(Filename)</DependentUpon>
</Compile>
<Compile Update="Screens\Sidebar\Views\SidebarView.axaml.cs">
<DependentUpon>SidebarView.axaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Update="Screens\Root\Views\RootView.axaml.cs">
<DependentUpon>RootView.axaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
</ItemGroup>
<ItemGroup>
<UpToDateCheckInput Remove="Views\MainWindow.axaml" />
</ItemGroup>
<ItemGroup>
<Content Include="Assets\Images\Logo\bow-black.ico" />
<Content Include="Assets\Images\Logo\bow-white.ico" />
<Content Include="Assets\Images\Logo\bow.ico" />
</ItemGroup>
<ItemGroup>
<Reference Include="RGB.NET.Core">
<HintPath>..\..\..\RGB.NET\bin\net5.0\RGB.NET.Core.dll</HintPath>
</Reference>
</ItemGroup>
<ItemGroup>
<Resource Include="Assets\Images\Logo\bow-black.ico" />
<Resource Include="Assets\Images\Logo\bow-white.ico" />
<Resource Include="Assets\Images\Logo\bow-white.svg" />
<Resource Include="Assets\Images\Logo\bow.ico" />
<Resource Include="Assets\Images\Logo\bow.svg" />
</ItemGroup>
</Project>

View File

@ -5,9 +5,9 @@
<Nullable>enable</Nullable>
</PropertyGroup>
<ItemGroup>
<Folder Include="Controls\" />
<Folder Include="Models\" />
<AvaloniaResource Include="Assets\**" />
<Folder Include="Utilities\" />
</ItemGroup>
<ItemGroup>
<None Remove="Assets\Images\home-banner.png" />

View File

@ -1,6 +1,7 @@
using System;
using Artemis.UI.Avalonia.Ninject.Factories;
using Artemis.UI.Avalonia.Screens;
using Artemis.UI.Avalonia.Services.Interfaces;
using Ninject.Extensions.Conventions;
using Ninject.Modules;
using Ninject.Planning.Bindings.Resolvers;
@ -40,6 +41,16 @@ namespace Artemis.UI.Avalonia.Ninject
.InheritedFrom<IVmFactory>()
.BindToFactory();
});
// Bind all UI services as singletons
Kernel.Bind(x =>
{
x.FromThisAssembly()
.SelectAllClasses()
.InheritedFrom<IArtemisUIService>()
.BindAllInterfaces()
.Configure(c => c.InSingletonScope());
});
}
}
}

View File

@ -1,13 +1,10 @@
using Avalonia;
using Avalonia.ReactiveUI;
using Ninject;
namespace Artemis.UI.Avalonia
{
internal class Program
{
private static StandardKernel _kernel;
// Initialization code. Don't use any Avalonia, third-party APIs or any
// SynchronizationContext-reliant code before AppMain is called: things aren't initialized
// yet and stuff might break.

View File

@ -11,8 +11,7 @@ namespace Artemis.UI.Avalonia.Screens.Root.ViewModels
{
private readonly IProfileService _profileService;
private readonly ISidebarVmFactory _vmFactory;
private SidebarProfileConfigurationViewModel _selectedProfileConfiguration;
public ProfileCategory ProfileCategory { get; }
private SidebarProfileConfigurationViewModel? _selectedProfileConfiguration;
public SidebarCategoryViewModel(ProfileCategory profileCategory, IProfileService profileService, ISidebarVmFactory vmFactory)
{
@ -25,9 +24,11 @@ namespace Artemis.UI.Avalonia.Screens.Root.ViewModels
CreateProfileViewModels();
}
public ProfileCategory ProfileCategory { get; }
public ObservableCollection<SidebarProfileConfigurationViewModel> ProfileConfigurations { get; } = new();
public SidebarProfileConfigurationViewModel SelectedProfileConfiguration
public SidebarProfileConfigurationViewModel? SelectedProfileConfiguration
{
get => _selectedProfileConfiguration;
set => this.RaiseAndSetIfChanged(ref _selectedProfileConfiguration, value);

View File

@ -29,7 +29,6 @@ namespace Artemis.UI.Avalonia.Screens.Root.ViewModels
}
public MaterialIconKind Icon { get; }
public string DisplayName { get; }
public abstract Type ScreenType { get; }
public abstract MainScreenViewModel CreateInstance(IKernel kernel, IScreen screen);

View File

@ -1,16 +1,164 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Reactive;
using System.Threading;
using System.Threading.Tasks;
using Artemis.Core;
using Artemis.Core.LayerBrushes;
using Artemis.Core.Services;
using Artemis.UI.Avalonia.Services.Interfaces;
using ReactiveUI;
using Serilog.Events;
namespace Artemis.UI.Avalonia.Screens.Settings.ViewModels
{
public class GeneralTabViewModel : ActivatableViewModelBase
{
public GeneralTabViewModel()
private readonly PluginSetting<LayerBrushReference> _defaultLayerBrushDescriptor;
private readonly ISettingsService _settingsService;
public GeneralTabViewModel(ISettingsService settingsService, IPluginManagementService pluginManagementService, IDebugService debuggerService)
{
DisplayName = "General";
_settingsService = settingsService;
List<LayerBrushProvider> layerBrushProviders = pluginManagementService.GetFeaturesOfType<LayerBrushProvider>();
LayerBrushDescriptors = new ObservableCollection<LayerBrushDescriptor>(layerBrushProviders.SelectMany(l => l.LayerBrushDescriptors));
_defaultLayerBrushDescriptor = _settingsService.GetSetting("ProfileEditor.DefaultLayerBrushDescriptor", new LayerBrushReference
{
LayerBrushProviderId = "Artemis.Plugins.LayerBrushes.Color.ColorBrushProvider-92a9d6ba",
BrushType = "SolidBrush"
});
ShowLogs = ReactiveCommand.Create(ExecuteShowLogs);
CheckForUpdate = ReactiveCommand.CreateFromTask(ExecuteCheckForUpdate);
ShowSetupWizard = ReactiveCommand.Create(ExecuteShowSetupWizard);
ShowDebugger = ReactiveCommand.Create(ExecuteShowDebugger);
ShowDataFolder = ReactiveCommand.Create(ExecuteShowDataFolder);
}
public ReactiveCommand<Unit, Unit> ShowLogs { get; }
public ReactiveCommand<Unit, Unit> CheckForUpdate { get; }
public ReactiveCommand<Unit, Unit> ShowSetupWizard { get; }
public ReactiveCommand<Unit, Unit> ShowDebugger { get; }
public ReactiveCommand<Unit, Unit> ShowDataFolder { get; }
public ObservableCollection<LayerBrushDescriptor> LayerBrushDescriptors { get; }
public ObservableCollection<string> GraphicsContexts { get; } = new()
{
"Software",
"Vulkan"
};
public ObservableCollection<(string, double)> RenderScales { get; } = new()
{
new ValueTuple<string, double>("25%", 0.25),
new ValueTuple<string, double>("50%", 0.5),
new ValueTuple<string, double>("100%", 1)
};
public ObservableCollection<(string, int)> TargetFrameRates { get; } = new()
{
new ValueTuple<string, int>("10 FPS", 10),
new ValueTuple<string, int>("20 FPS", 20),
new ValueTuple<string, int>("30 FPS", 30),
new ValueTuple<string, int>("45 FPS", 45),
new ValueTuple<string, int>("60 FPS (lol)", 60),
new ValueTuple<string, int>("144 FPS (omegalol)", 144)
};
public LayerBrushDescriptor? SelectedLayerBrushDescriptor
{
get => LayerBrushDescriptors.FirstOrDefault(d => d.MatchesLayerBrushReference(_defaultLayerBrushDescriptor.Value));
set
{
if (value != null) _defaultLayerBrushDescriptor.Value = new LayerBrushReference(value);
}
}
public (string, double)? SelectedRenderScale
{
get => RenderScales.FirstOrDefault(s => Math.Abs(s.Item2 - CoreRenderScale.Value) < 0.01);
set
{
if (value != null) CoreRenderScale.Value = value.Value.Item2;
}
}
public (string, int)? SelectedTargetFrameRate
{
get => TargetFrameRates.FirstOrDefault(s => s.Item2 == CoreTargetFrameRate.Value);
set
{
if (value != null) CoreTargetFrameRate.Value = value.Value.Item2;
}
}
public PluginSetting<bool> UIAutoRun => _settingsService.GetSetting("UI.AutoRun", false);
public PluginSetting<int> UIAutoRunDelay => _settingsService.GetSetting("UI.AutoRunDelay", 15);
public PluginSetting<bool> UIShowOnStartup => _settingsService.GetSetting("UI.ShowOnStartup", true);
public PluginSetting<bool> UICheckForUpdates => _settingsService.GetSetting("UI.CheckForUpdates", true);
public PluginSetting<ApplicationColorScheme> UIColorScheme => _settingsService.GetSetting("UI.ColorScheme", ApplicationColorScheme.Automatic);
public PluginSetting<bool> ProfileEditorShowDataModelValues => _settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false);
public PluginSetting<LogEventLevel> CoreLoggingLevel => _settingsService.GetSetting("Core.LoggingLevel", LogEventLevel.Information);
public PluginSetting<string> CorePreferredGraphicsContext => _settingsService.GetSetting("Core.PreferredGraphicsContext", "Vulkan");
public PluginSetting<double> CoreRenderScale => _settingsService.GetSetting("Core.RenderScale", 0.25);
public PluginSetting<int> CoreTargetFrameRate => _settingsService.GetSetting("Core.TargetFrameRate", 30);
public PluginSetting<int> WebServerPort => _settingsService.GetSetting("WebServer.Port", 9696);
#region General
private void ExecuteShowLogs()
{
OpenFolder(Path.Combine(Constants.DataFolder, "Logs"));
}
#endregion
#region Updating
private Task ExecuteCheckForUpdate(CancellationToken cancellationToken)
{
return Task.CompletedTask;
}
#endregion
#region Tools
private void ExecuteShowSetupWizard()
{
}
private void ExecuteShowDebugger()
{
}
private void ExecuteShowDataFolder()
{
OpenFolder(Constants.DataFolder);
}
#endregion
private void OpenFolder(string path)
{
if (OperatingSystem.IsWindows())
{
Process.Start(Environment.GetEnvironmentVariable("WINDIR") + @"\explorer.exe", path);
}
}
}
}
public enum ApplicationColorScheme
{
Light,
Dark,
Automatic
}
}

View File

@ -2,7 +2,355 @@
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"
xmlns:system="clr-namespace:System;assembly=System.Runtime"
xmlns:controls="clr-namespace:Artemis.UI.Avalonia.Shared.Controls;assembly=Artemis.UI.Avalonia.Shared"
xmlns:layerBrushes="clr-namespace:Artemis.Core.LayerBrushes;assembly=Artemis.Core"
xmlns:avalonia="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia"
mc:Ignorable="d" d:DesignWidth="1000" d:DesignHeight="2400"
x:Class="Artemis.UI.Avalonia.Screens.Settings.Views.GeneralTabView">
Welcome to Avalonia!
</UserControl>
<StackPanel Margin="15" MaxWidth="1000">
<!-- General settings -->
<TextBlock Classes="h4" Margin="0 15">
General
</TextBlock>
<Border Classes="card" VerticalAlignment="Stretch" Margin="0,0,5,0">
<StackPanel>
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0">
<TextBlock>Auto-run on startup</TextBlock>
</StackPanel>
<ToggleSwitch Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" IsChecked="{Binding UIAutoRun.Value}" MinWidth="0" Margin="0 -10"/>
</Grid>
<Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0">
<TextBlock>Hide window on auto-run</TextBlock>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ToggleSwitch IsChecked="{Binding !UIShowOnStartup.Value}" IsEnabled="{Binding UIAutoRun.Value}" MinWidth="0" Margin="0 -10"/>
</StackPanel>
</Grid>
<Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0">
<TextBlock>Startup delay</TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap">
Set the amount of seconds to wait before auto-running Artemis.
</TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap">
If some devices don't work because Artemis starts before the manufacturer's software, try increasing this value.
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" Orientation="Horizontal">
<TextBox Text="{Binding UIAutoRunDelay.Value}" IsEnabled="{Binding UIAutoRun.Value}" Width="120" />
<TextBlock VerticalAlignment="Center" TextAlignment="Right" Width="30">sec</TextBlock>
</StackPanel>
</Grid>
<Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0">
<TextBlock>Color scheme</TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap">
Pick between a light and dark color scheme, the automatic option copies your system settings.
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<controls:EnumComboBox Width="150" Value="{Binding UIColorScheme.Value}" />
</StackPanel>
</Grid>
<Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0">
<TextBlock>
Log level
</TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap">
Sets the logging level, a higher logging level will result in more log files.
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<controls:EnumComboBox Width="150" Value="{Binding CoreLoggingLevel.Value}" />
</StackPanel>
</Grid>
<Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" VerticalAlignment="Center">
<TextBlock>
Logs
</TextBlock>
<TextBlock Classes="subtitle">
Opens the directory where logs are stored.
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<Button Command="{Binding ShowLogs}" Width="150" Content="Show logs" />
</StackPanel>
</Grid>
</StackPanel>
</Border>
<!-- Web server settings -->
<TextBlock Classes="h4" Margin="0 15">
Web server
</TextBlock>
<Border Classes="card" VerticalAlignment="Stretch" Margin="0,0,5,0">
<StackPanel>
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0">
<TextBlock>
Web server port
</TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap">
Artemis runs a local web server that can be used to externally interact with the application.
</TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap">
This web server can only be accessed by applications running on your own computer, e.g. supported games.
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<TextBox Text="{Binding WebServerPort.Value}" Width="150" />
</StackPanel>
</Grid>
</StackPanel>
</Border>
<!-- Update settings -->
<TextBlock Classes="h4" Margin="0 15">
Updating
</TextBlock>
<Border Classes="card" VerticalAlignment="Stretch" Margin="0,0,5,0">
<StackPanel>
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0">
<TextBlock>
Check for updates
</TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap">
If enabled, we'll check for updates on startup and periodically while running.
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ToggleSwitch IsChecked="{Binding UICheckForUpdates.Value}" MinWidth="0" />
</StackPanel>
</Grid>
<Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" VerticalAlignment="Center">
<TextBlock>
Update
</TextBlock>
<TextBlock Classes="subtitle">
Use the button on the right to check for updates now.
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<Button Command="{Binding OfferUpdatesIfFound}" Width="150" Content="Check now" />
</StackPanel>
</Grid>
</StackPanel>
</Border>
<!-- Profile editor settings -->
<TextBlock Classes="h4" Margin="0 15">
Profile editor
</TextBlock>
<Border Classes="card" VerticalAlignment="Stretch" Margin="0,0,5,0">
<StackPanel>
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0">
<TextBlock>
Show condition data model values
</TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap">
While selecting a condition target, show the current values of the data model.
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ToggleSwitch IsChecked="{Binding ProfileEditorShowDataModelValues.Value}" MinWidth="0" />
</StackPanel>
</Grid>
<Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0">
<TextBlock>
Default brush
</TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap">
Sets the default brush that is applied to new layers
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<StackPanel.Styles>
<Style Selector="ComboBox.brush /template/ ContentControl#ContentPresenter">
<Setter Property="ContentTemplate">
<Setter.Value>
<DataTemplate DataType="{x:Type layerBrushes:LayerBrushDescriptor}">
<StackPanel Orientation="Horizontal">
<avalonia:MaterialIcon Kind="{Binding Icon}" Height="20" Width="20" VerticalAlignment="Center" Margin="0 0 5 0"/>
<TextBlock Text="{Binding DisplayName}" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</StackPanel.Styles>
<ComboBox Classes="brush"
Width="200"
HorizontalAlignment="Left"
Items="{Binding LayerBrushDescriptors}"
SelectedItem="{Binding SelectedLayerBrushDescriptor}">
<ComboBox.ItemTemplate>
<DataTemplate DataType="{x:Type layerBrushes:LayerBrushDescriptor}">
<Grid ColumnDefinitions="30,*" RowDefinitions="Auto,Auto">
<avalonia:MaterialIcon Grid.Row="0"
Grid.RowSpan="2"
Kind="{Binding Icon}"
Height="20"
Width="20"
VerticalAlignment="Center"
HorizontalAlignment="Left" />
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding DisplayName}" TextWrapping="Wrap" MaxWidth="350" />
<TextBlock Classes="subtitle" Grid.Row="1" Grid.Column="1" Text="{Binding Description}" TextWrapping="Wrap" MaxWidth="350" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</Grid>
</StackPanel>
</Border>
<!-- Rendering settings -->
<TextBlock Classes="h4" Margin="0 15">
Rendering
</TextBlock>
<Border Classes="card" VerticalAlignment="Stretch" Margin="0,0,5,0">
<StackPanel>
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0">
<TextBlock>
Preferred render method
</TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap">
Software-based rendering is done purely on the CPU while Vulkan uses GPU-acceleration.
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ComboBox Width="150"
SelectedItem="{Binding CorePreferredGraphicsContext.Value}"
Items="{Binding GraphicsContexts}"/>
</StackPanel>
</Grid>
<Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0">
<TextBlock>
Render scale
</TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap">
Sets the resolution Artemis renders at, higher scale means more CPU-usage, especially on large surfaces.
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ComboBox Width="150"
SelectedItem="{Binding SelectedRenderScale}"
Items="{Binding RenderScales}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding [0]}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</Grid>
<Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0">
<TextBlock>
Target frame rate
</TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap">
Sets the FPS Artemis tries to render at, higher FPS means more CPU-usage but smoother animations.
</TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap">
The options past 45 FPS are mostly useless unless you are using a custom device.
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ComboBox Width="150"
SelectedItem="{Binding SelectedTargetFrameRate}"
Items="{Binding TargetFrameRates}">
<ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding [0]}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</Grid>
</StackPanel>
</Border>
<!-- Tools -->
<TextBlock Classes="h4" Margin="0 15">
Tools
</TextBlock>
<Border Classes="card" VerticalAlignment="Stretch" Margin="0,0,5,0">
<StackPanel>
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" VerticalAlignment="Center">
<TextBlock>
Setup wizard
</TextBlock>
<TextBlock Classes="subtitle">
Opens the startup wizard usually shown when Artemis first starts.
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<Button Command="{Binding ShowSetupWizard}" Width="150" Content="Show wizard" />
</StackPanel>
</Grid>
<Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" VerticalAlignment="Center">
<TextBlock>
Debugger
</TextBlock>
<TextBlock Classes="subtitle">
Use the debugger to see the raw image Artemis is rendering on the surface.
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<Button Command="{Binding ShowDebugger}" Width="150" Content="Show debugger" />
</StackPanel>
</Grid>
<Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" VerticalAlignment="Center">
<TextBlock>
Application files
</TextBlock>
<TextBlock Classes="subtitle">
Opens the directory where application files like plugins and settings are stored.
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<Button Command="{Binding ShowDataFolder}" Width="150" Content="Show app files" />
</StackPanel>
</Grid>
</StackPanel>
</Border>
</StackPanel>
</UserControl>

View File

@ -1,10 +1,12 @@
using Artemis.UI.Avalonia.Screens.Settings.ViewModels;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.ReactiveUI;
namespace Artemis.UI.Avalonia.Screens.Settings.Views
{
public partial class GeneralTabView : UserControl
public partial class GeneralTabView : ReactiveUserControl<GeneralTabViewModel>
{
public GeneralTabView()
{

View File

@ -0,0 +1,33 @@
using Artemis.UI.Avalonia.Screens.Debug;
using Artemis.UI.Avalonia.Services.Interfaces;
using Ninject;
namespace Artemis.UI.Avalonia.Services
{
public class DebugService : IDebugService
{
private readonly IKernel _kernel;
private DebugWindow? _debugWindow;
public DebugService(IKernel kernel)
{
_kernel = kernel;
}
private void CreateDebugger()
{
}
private void BringDebuggerToForeground()
{
}
public void ShowDebugger()
{
if (_debugWindow != null)
BringDebuggerToForeground();
else
CreateDebugger();
}
}
}

View File

@ -0,0 +1,6 @@
namespace Artemis.UI.Avalonia.Services.Interfaces
{
public interface IArtemisUIService
{
}
}

View File

@ -0,0 +1,13 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Artemis.UI.Avalonia.Services.Interfaces
{
public interface IDebugService : IArtemisUIService
{
void ShowDebugger();
}
}

View File

@ -3,6 +3,7 @@ using Artemis.Core;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Services;
using Stylet;
using EnumUtilities = Artemis.UI.Shared.EnumUtilities;
namespace Artemis.UI.DefaultTypes.PropertyInput
{

View File

@ -10,6 +10,7 @@ using Artemis.UI.Screens.ProfileEditor.LayerProperties.Timeline;
using Artemis.UI.Shared;
using Artemis.UI.Shared.Services;
using Stylet;
using EnumUtilities = Artemis.UI.Shared.EnumUtilities;
namespace Artemis.UI.Screens.ProfileEditor.LayerProperties.DataBindings
{

View File

@ -1,6 +1,7 @@
using Artemis.Core;
using Artemis.UI.Shared;
using Stylet;
using EnumUtilities = Artemis.UI.Shared.EnumUtilities;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints
{

View File

@ -2,6 +2,7 @@
using Artemis.UI.Shared;
using RGB.NET.Core;
using Stylet;
using EnumUtilities = Artemis.UI.Shared.EnumUtilities;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints
{

View File

@ -1,6 +1,7 @@
using Artemis.Core;
using Artemis.UI.Shared;
using Stylet;
using EnumUtilities = Artemis.UI.Shared.EnumUtilities;
namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.Dialogs.AdaptionHints
{

View File

@ -54,8 +54,6 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
_registrationService = registrationService;
_messageService = messageService;
LogLevels = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(LogEventLevel)));
ColorSchemes = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(ApplicationColorScheme)));
RenderScales = new BindableCollection<Tuple<string, double>>
{
new("25%", 0.25),

View File

@ -17,6 +17,7 @@ using FluentValidation;
using MaterialDesignThemes.Wpf;
using Ookii.Dialogs.Wpf;
using Stylet;
using EnumUtilities = Artemis.UI.Shared.EnumUtilities;
namespace Artemis.UI.Screens.Sidebar.Dialogs.ProfileEdit
{

View File

@ -9,6 +9,7 @@ using Artemis.UI.Shared;
using Artemis.UI.Shared.Services;
using Artemis.UI.Utilities;
using Stylet;
using EnumUtilities = Artemis.UI.Shared.EnumUtilities;
namespace Artemis.UI.Screens.StartupWizard.Steps
{