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

UI - Moved color scheme code away from tray VM

UI - Cleaned up settings page code
Core - Changed default framerate to 30
This commit is contained in:
Robert 2021-09-18 20:40:57 +02:00
parent da123e2fe2
commit ef4e5b4c3b
14 changed files with 504 additions and 463 deletions

View File

@ -11,18 +11,14 @@ namespace Artemis.Core
/// Represents a setting tied to a plugin of type <typeparamref name="T" /> /// Represents a setting tied to a plugin of type <typeparamref name="T" />
/// </summary> /// </summary>
/// <typeparam name="T">The value type of the setting</typeparam> /// <typeparam name="T">The value type of the setting</typeparam>
public class PluginSetting<T> : CorePropertyChanged public class PluginSetting<T> : CorePropertyChanged, IPluginSetting
{ {
// TODO: Why? Should have included that...
// ReSharper disable once NotAccessedField.Local
private readonly Plugin _plugin;
private readonly IPluginRepository _pluginRepository; private readonly IPluginRepository _pluginRepository;
private readonly PluginSettingEntity _pluginSettingEntity; private readonly PluginSettingEntity _pluginSettingEntity;
private T _value; private T _value;
internal PluginSetting(Plugin plugin, IPluginRepository pluginRepository, PluginSettingEntity pluginSettingEntity) internal PluginSetting(IPluginRepository pluginRepository, PluginSettingEntity pluginSettingEntity)
{ {
_plugin = plugin;
_pluginRepository = pluginRepository; _pluginRepository = pluginRepository;
_pluginSettingEntity = pluginSettingEntity; _pluginSettingEntity = pluginSettingEntity;
@ -37,9 +33,7 @@ namespace Artemis.Core
} }
} }
/// <summary> /// <inheritdoc />
/// The name of the setting, unique to this plugin
/// </summary>
public string Name { get; } public string Name { get; }
/// <summary> /// <summary>
@ -63,28 +57,19 @@ namespace Artemis.Core
} }
} }
/// <summary> /// <inheritdoc />
/// Determines whether the setting has been changed
/// </summary>
public bool HasChanged => CoreJson.SerializeObject(Value) != _pluginSettingEntity.Value; public bool HasChanged => CoreJson.SerializeObject(Value) != _pluginSettingEntity.Value;
/// <summary> /// <inheritdoc />
/// Gets or sets whether changes must automatically be saved
/// <para>Note: When set to <c>true</c> <see cref="HasChanged" /> is always <c>false</c></para>
/// </summary>
public bool AutoSave { get; set; } public bool AutoSave { get; set; }
/// <summary> /// <inheritdoc />
/// Resets the setting to the last saved value
/// </summary>
public void RejectChanges() public void RejectChanges()
{ {
Value = CoreJson.DeserializeObject<T>(_pluginSettingEntity.Value); Value = CoreJson.DeserializeObject<T>(_pluginSettingEntity.Value);
} }
/// <summary> /// <inheritdoc />
/// Saves the setting
/// </summary>
public void Save() public void Save()
{ {
if (!HasChanged) if (!HasChanged)
@ -95,14 +80,10 @@ namespace Artemis.Core
OnSettingSaved(); OnSettingSaved();
} }
/// <summary> /// <inheritdoc />
/// Occurs when the value of the setting has been changed
/// </summary>
public event EventHandler? SettingChanged; public event EventHandler? SettingChanged;
/// <summary> /// <inheritdoc />
/// Occurs when the value of the setting has been saved
/// </summary>
public event EventHandler? SettingSaved; public event EventHandler? SettingSaved;
/// <inheritdoc /> /// <inheritdoc />
@ -127,4 +108,46 @@ namespace Artemis.Core
SettingSaved?.Invoke(this, EventArgs.Empty); SettingSaved?.Invoke(this, EventArgs.Empty);
} }
} }
/// <summary>
/// Represents a setting tied to a plugin
/// </summary>
public interface IPluginSetting
{
/// <summary>
/// The name of the setting, unique to this plugin
/// </summary>
string Name { get; }
/// <summary>
/// Determines whether the setting has been changed
/// </summary>
bool HasChanged { get; }
/// <summary>
/// Gets or sets whether changes must automatically be saved
/// <para>Note: When set to <c>true</c> <see cref="HasChanged" /> is always <c>false</c></para>
/// </summary>
bool AutoSave { get; set; }
/// <summary>
/// Resets the setting to the last saved value
/// </summary>
void RejectChanges();
/// <summary>
/// Saves the setting
/// </summary>
void Save();
/// <summary>
/// Occurs when the value of the setting has been changed
/// </summary>
event EventHandler? SettingChanged;
/// <summary>
/// Occurs when the value of the setting has been saved
/// </summary>
event EventHandler? SettingSaved;
}
} }

View File

@ -1,7 +1,6 @@
using System.Collections.Generic; using System.Collections.Generic;
using Artemis.Storage.Entities.Plugins; using Artemis.Storage.Entities.Plugins;
using Artemis.Storage.Repositories.Interfaces; using Artemis.Storage.Repositories.Interfaces;
using Newtonsoft.Json;
namespace Artemis.Core namespace Artemis.Core
{ {
@ -12,7 +11,7 @@ namespace Artemis.Core
public class PluginSettings public class PluginSettings
{ {
private readonly IPluginRepository _pluginRepository; private readonly IPluginRepository _pluginRepository;
private readonly Dictionary<string, object> _settingEntities; private readonly Dictionary<string, IPluginSetting> _settingEntities;
internal PluginSettings(Plugin plugin, IPluginRepository pluginRepository) internal PluginSettings(Plugin plugin, IPluginRepository pluginRepository)
{ {
@ -20,7 +19,7 @@ namespace Artemis.Core
Plugin.Settings = this; Plugin.Settings = this;
_pluginRepository = pluginRepository; _pluginRepository = pluginRepository;
_settingEntities = new Dictionary<string, object>(); _settingEntities = new Dictionary<string, IPluginSetting>();
} }
/// <summary> /// <summary>
@ -56,7 +55,7 @@ namespace Artemis.Core
_pluginRepository.AddSetting(settingEntity); _pluginRepository.AddSetting(settingEntity);
} }
PluginSetting<T> pluginSetting = new(Plugin, _pluginRepository, settingEntity); PluginSetting<T> pluginSetting = new(_pluginRepository, settingEntity);
// This overrides null with the default value, I'm not sure if that's desirable because you // This overrides null with the default value, I'm not sure if that's desirable because you
// might expect something to go null and you might not // might expect something to go null and you might not
@ -68,6 +67,15 @@ namespace Artemis.Core
} }
} }
/// <summary>
/// Saves all currently loaded settings
/// </summary>
public void SaveAllSettings()
{
foreach (var (_, pluginSetting) in _settingEntities)
pluginSetting.Save();
}
internal void ClearSettings() internal void ClearSettings()
{ {
_settingEntities.Clear(); _settingEntities.Clear();

View File

@ -35,7 +35,7 @@ namespace Artemis.Core.Services
_logger = logger; _logger = logger;
_pluginManagementService = pluginManagementService; _pluginManagementService = pluginManagementService;
_deviceRepository = deviceRepository; _deviceRepository = deviceRepository;
_targetFrameRateSetting = settingsService.GetSetting("Core.TargetFrameRate", 25); _targetFrameRateSetting = settingsService.GetSetting("Core.TargetFrameRate", 30);
_renderScaleSetting = settingsService.GetSetting("Core.RenderScale", 0.25); _renderScaleSetting = settingsService.GetSetting("Core.RenderScale", 0.25);
Surface = new RGBSurface(); Surface = new RGBSurface();

View File

@ -16,6 +16,12 @@ namespace Artemis.Core.Services
{ {
return _pluginSettings.GetSetting(name, defaultValue); return _pluginSettings.GetSetting(name, defaultValue);
} }
/// <inheritdoc />
public void SaveAllSettings()
{
_pluginSettings.SaveAllSettings();
}
} }
/// <summary> /// <summary>
@ -32,5 +38,10 @@ namespace Artemis.Core.Services
/// <param name="defaultValue">The default value to use if the setting does not exist yet</param> /// <param name="defaultValue">The default value to use if the setting does not exist yet</param>
/// <returns></returns> /// <returns></returns>
PluginSetting<T> GetSetting<T>(string name, T? defaultValue = default); PluginSetting<T> GetSetting<T>(string name, T? defaultValue = default);
/// <summary>
/// Saves all settings, obviously
/// </summary>
void SaveAllSettings();
} }
} }

View File

@ -0,0 +1,30 @@
using System;
using System.Globalization;
using System.Windows.Data;
namespace Artemis.UI.Converters
{
[ValueConversion(typeof(double), typeof(double))]
public class NormalizedPercentageConverter : IValueConverter
{
#region IValueConverter Members
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is double number)
return number * 100.0;
return value;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is double number)
return number / 100.0;
return value;
}
#endregion
}
}

View File

@ -1,15 +1,16 @@
using System; using System;
using Artemis.UI.Services;
using Artemis.UI.Utilities; using Artemis.UI.Utilities;
namespace Artemis.UI.Events namespace Artemis.UI.Events
{ {
public class WindowsThemeEventArgs : EventArgs public class WindowsThemeEventArgs : EventArgs
{ {
public WindowsThemeEventArgs(ThemeWatcher.WindowsTheme theme) public WindowsThemeEventArgs(IThemeService.WindowsTheme theme)
{ {
Theme = theme; Theme = theme;
} }
public ThemeWatcher.WindowsTheme Theme { get; set; } public IThemeService.WindowsTheme Theme { get; set; }
} }
} }

View File

@ -4,8 +4,8 @@ using System.IO;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using Windows.UI.Notifications; using Windows.UI.Notifications;
using Artemis.UI.Services;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
using Artemis.UI.Utilities;
using MaterialDesignThemes.Wpf; using MaterialDesignThemes.Wpf;
using Microsoft.Toolkit.Uwp.Notifications; using Microsoft.Toolkit.Uwp.Notifications;
using Stylet; using Stylet;
@ -14,11 +14,11 @@ namespace Artemis.UI.Providers
{ {
public class ToastNotificationProvider : INotificationProvider public class ToastNotificationProvider : INotificationProvider
{ {
private ThemeWatcher _themeWatcher; private readonly IThemeService _themeService;
public ToastNotificationProvider() public ToastNotificationProvider(IThemeService themeService)
{ {
_themeWatcher = new ThemeWatcher(); _themeService = themeService;
} }
public static PngBitmapEncoder GetEncoderForIcon(PackIconKind icon, Color color) public static PngBitmapEncoder GetEncoderForIcon(PackIconKind icon, Color color)
@ -71,7 +71,7 @@ namespace Artemis.UI.Providers
Execute.OnUIThreadSync(() => Execute.OnUIThreadSync(() =>
{ {
using FileStream stream = File.OpenWrite(imagePath); using FileStream stream = File.OpenWrite(imagePath);
GetEncoderForIcon(icon, _themeWatcher.GetSystemTheme() == ThemeWatcher.WindowsTheme.Dark ? Colors.White : Colors.Black).Save(stream); GetEncoderForIcon(icon, _themeService.GetSystemTheme() == IThemeService.WindowsTheme.Dark ? Colors.White : Colors.Black).Save(stream);
}); });
new ToastContentBuilder() new ToastContentBuilder()
@ -88,14 +88,10 @@ namespace Artemis.UI.Providers
#endregion #endregion
#region IDisposable
/// <inheritdoc /> /// <inheritdoc />
public void Dispose() public void Dispose()
{ {
ToastNotificationManagerCompat.Uninstall(); ToastNotificationManagerCompat.Uninstall();
} }
#endregion
} }
} }

View File

@ -512,7 +512,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
if (SelectedProfileElement == null) if (SelectedProfileElement == null)
return; return;
double frameTime = 1000.0 / SettingsService.GetSetting("Core.TargetFrameRate", 25).Value; double frameTime = 1000.0 / SettingsService.GetSetting("Core.TargetFrameRate", 30).Value;
double newTime = Math.Max(0, Math.Round((ProfileEditorService.CurrentTime.TotalMilliseconds - frameTime) / frameTime) * frameTime); double newTime = Math.Max(0, Math.Round((ProfileEditorService.CurrentTime.TotalMilliseconds - frameTime) / frameTime) * frameTime);
ProfileEditorService.CurrentTime = TimeSpan.FromMilliseconds(newTime); ProfileEditorService.CurrentTime = TimeSpan.FromMilliseconds(newTime);
} }
@ -522,7 +522,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
if (SelectedProfileElement == null) if (SelectedProfileElement == null)
return; return;
double frameTime = 1000.0 / SettingsService.GetSetting("Core.TargetFrameRate", 25).Value; double frameTime = 1000.0 / SettingsService.GetSetting("Core.TargetFrameRate", 30).Value;
double newTime = Math.Round((ProfileEditorService.CurrentTime.TotalMilliseconds + frameTime) / frameTime) * frameTime; double newTime = Math.Round((ProfileEditorService.CurrentTime.TotalMilliseconds + frameTime) / frameTime) * frameTime;
newTime = Math.Min(newTime, SelectedProfileElement.Timeline.EndSegmentEndPosition.TotalMilliseconds); newTime = Math.Min(newTime, SelectedProfileElement.Timeline.EndSegmentEndPosition.TotalMilliseconds);
ProfileEditorService.CurrentTime = TimeSpan.FromMilliseconds(newTime); ProfileEditorService.CurrentTime = TimeSpan.FromMilliseconds(newTime);

View File

@ -1,27 +1,32 @@
<UserControl x:Class="Artemis.UI.Screens.Settings.Tabs.General.GeneralSettingsTabView" <UserControl
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Settings.Tabs.General" xmlns:local="clr-namespace:Artemis.UI.Screens.Settings.Tabs.General"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:s="https://github.com/canton7/Stylet" xmlns:s="https://github.com/canton7/Stylet"
xmlns:dataTemplateSelectors="clr-namespace:Artemis.UI.DataTemplateSelectors" xmlns:dataTemplateSelectors="clr-namespace:Artemis.UI.DataTemplateSelectors"
xmlns:system="clr-namespace:System;assembly=System.Runtime" xmlns:system="clr-namespace:System;assembly=System.Runtime"
mc:Ignorable="d" xmlns:Converters="clr-namespace:Artemis.UI.Converters" x:Class="Artemis.UI.Screens.Settings.Tabs.General.GeneralSettingsTabView"
d:DesignHeight="450" d:DesignWidth="800" mc:Ignorable="d"
d:DataContext="{d:DesignInstance local:GeneralSettingsTabViewModel}"> d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance {x:Type local:GeneralSettingsTabViewModel}}">
<UserControl.Resources> <UserControl.Resources>
<ResourceDictionary> <ResourceDictionary>
<ResourceDictionary.MergedDictionaries> <ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Artemis.UI;component/ResourceDictionaries/LayerBrushDescriptors.xaml" /> <ResourceDictionary Source="pack://application:,,,/Artemis.UI;component/ResourceDictionaries/LayerBrushDescriptors.xaml" />
</ResourceDictionary.MergedDictionaries> </ResourceDictionary.MergedDictionaries>
<Converters:InverseBooleanConverter x:Key="InverseBooleanConverter" />
<Converters:NormalizedPercentageConverter x:Key="NormalizedPercentageConverter" />
</ResourceDictionary> </ResourceDictionary>
</UserControl.Resources> </UserControl.Resources>
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled"> <ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
<StackPanel Margin="15" MaxWidth="800"> <StackPanel Margin="15" MaxWidth="800">
<!-- General settings --> <!-- General settings -->
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" Margin="0 15">General</TextBlock> <TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" Margin="0 15">
<Run Text="General" />
</TextBlock>
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch" Margin="0,0,5,0"> <materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch" Margin="0,0,5,0">
<StackPanel Margin="15"> <StackPanel Margin="15">
<Grid> <Grid>
@ -37,7 +42,7 @@
<TextBlock Style="{StaticResource MaterialDesignTextBlock}">Start up with Windows</TextBlock> <TextBlock Style="{StaticResource MaterialDesignTextBlock}">Start up with Windows</TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ToggleButton Style="{StaticResource MaterialDesignSwitchToggleButton}" IsChecked="{Binding StartWithWindows}" /> <ToggleButton Style="{StaticResource MaterialDesignSwitchToggleButton}" IsChecked="{Binding UIAutoRun.Value}" />
</StackPanel> </StackPanel>
</Grid> </Grid>
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" /> <Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
@ -55,7 +60,9 @@
<TextBlock Style="{StaticResource MaterialDesignTextBlock}">Start up with Windows minimized</TextBlock> <TextBlock Style="{StaticResource MaterialDesignTextBlock}">Start up with Windows minimized</TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ToggleButton Style="{StaticResource MaterialDesignSwitchToggleButton}" IsChecked="{Binding StartMinimized}" IsEnabled="{Binding StartWithWindows}" /> <ToggleButton Style="{StaticResource MaterialDesignSwitchToggleButton}"
IsChecked="{Binding UIShowOnStartup.Value, Converter={StaticResource InverseBooleanConverter}}"
IsEnabled="{Binding UIAutoRun.Value}" />
</StackPanel> </StackPanel>
</Grid> </Grid>
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" /> <Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
@ -72,14 +79,14 @@
<StackPanel Grid.Column="0"> <StackPanel Grid.Column="0">
<TextBlock Style="{StaticResource MaterialDesignTextBlock}">Startup delay</TextBlock> <TextBlock Style="{StaticResource MaterialDesignTextBlock}">Startup delay</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap"> <TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap">
Set the amount of seconds to wait before running Artemis with Windows. <LineBreak /> <Run Text="Set the amount of seconds to wait before running Artemis with Windows." /><LineBreak />
If some devices don't work because Artemis starts before the manufacturer's software, try increasing this value. <Run Text="If some devices don't work because Artemis starts before the manufacturer's software, try increasing this value." />
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<TextBox Style="{StaticResource MaterialDesignFilledTextBox}" <TextBox Style="{StaticResource MaterialDesignFilledTextBox}"
Text="{Binding AutoRunDelay}" Text="{Binding UIAutoRunDelay.Value}"
IsEnabled="{Binding StartWithWindows}" IsEnabled="{Binding UIAutoRun.Value}"
Width="100" Width="100"
materialDesign:TextFieldAssist.SuffixText="sec" materialDesign:TextFieldAssist.SuffixText="sec"
materialDesign:HintAssist.IsFloating="false" /> materialDesign:HintAssist.IsFloating="false" />
@ -105,7 +112,7 @@
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ComboBox Style="{StaticResource MaterialDesignFilledComboBox}" <ComboBox Style="{StaticResource MaterialDesignFilledComboBox}"
Width="100" Width="100"
SelectedValue="{Binding SelectedColorScheme}" SelectedValue="{Binding UIColorScheme.Value}"
ItemsSource="{Binding ColorSchemes}" ItemsSource="{Binding ColorSchemes}"
SelectedValuePath="Value" SelectedValuePath="Value"
DisplayMemberPath="Description" DisplayMemberPath="Description"
@ -124,7 +131,9 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"> <StackPanel Grid.Column="0">
<TextBlock Style="{StaticResource MaterialDesignTextBlock}">Log level</TextBlock> <TextBlock Style="{StaticResource MaterialDesignTextBlock}">
Log level
</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap"> <TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap">
Sets the logging level, a higher logging level will result in more log files. Sets the logging level, a higher logging level will result in more log files.
</TextBlock> </TextBlock>
@ -132,7 +141,7 @@
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ComboBox Style="{StaticResource MaterialDesignFilledComboBox}" <ComboBox Style="{StaticResource MaterialDesignFilledComboBox}"
Width="100" Width="100"
SelectedValue="{Binding SelectedLogLevel}" SelectedValue="{Binding CoreLoggingLevel.Value}"
ItemsSource="{Binding LogLevels}" ItemsSource="{Binding LogLevels}"
SelectedValuePath="Value" SelectedValuePath="Value"
DisplayMemberPath="Description" DisplayMemberPath="Description"
@ -151,22 +160,24 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" VerticalAlignment="Center"> <StackPanel Grid.Column="0" VerticalAlignment="Center">
<TextBlock Style="{StaticResource MaterialDesignTextBlock}">Logs</TextBlock> <TextBlock Style="{StaticResource MaterialDesignTextBlock}">
Logs
</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}"> <TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}">
Opens the directory where logs are stored. Opens the directory where logs are stored.
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<Button Style="{StaticResource MaterialDesignOutlinedButton}" Command="{s:Action ShowLogsFolder}" Width="150"> <Button Style="{StaticResource MaterialDesignOutlinedButton}" Command="{s:Action ShowLogsFolder}" Width="150" Content="SHOW LOGS" />
SHOW LOGS
</Button>
</StackPanel> </StackPanel>
</Grid> </Grid>
</StackPanel> </StackPanel>
</materialDesign:Card> </materialDesign:Card>
<!-- Web server settings --> <!-- Web server settings -->
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" Margin="0 15">Web server</TextBlock> <TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" Margin="0 15">
Web server
</TextBlock>
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch" Margin="0,0,5,0"> <materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch" Margin="0,0,5,0">
<StackPanel Margin="15"> <StackPanel Margin="15">
<Grid> <Grid>
@ -179,14 +190,18 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"> <StackPanel Grid.Column="0">
<TextBlock Style="{StaticResource MaterialDesignTextBlock}">Web server port</TextBlock> <TextBlock Style="{StaticResource MaterialDesignTextBlock}">
Web server port
</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap"> <TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap">
Artemis runs a local web server that can be used to externally interact with the application. <LineBreak /> <Run Text="Artemis runs a local web server that can be used to externally interact with the application." /><LineBreak />
This web server can only be accessed by applications running on your own computer, e.g. supported games. <Run Text="This web server can only be accessed by applications running on your own computer, e.g. supported games." />
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<TextBox Style="{StaticResource MaterialDesignFilledTextBox}" Text="{Binding WebServerPortSetting.Value}" Width="100" <TextBox Style="{StaticResource MaterialDesignFilledTextBox}"
Text="{Binding WebServerPort.Value}"
Width="100"
materialDesign:HintAssist.IsFloating="false" /> materialDesign:HintAssist.IsFloating="false" />
</StackPanel> </StackPanel>
</Grid> </Grid>
@ -194,7 +209,9 @@
</materialDesign:Card> </materialDesign:Card>
<!-- Update settings --> <!-- Update settings -->
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" Margin="0 15">Updating</TextBlock> <TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" Margin="0 15">
<Run Text="Updating" />
</TextBlock>
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch" Margin="0,0,5,0"> <materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch" Margin="0,0,5,0">
<StackPanel Margin="15"> <StackPanel Margin="15">
<Grid> <Grid>
@ -207,13 +224,15 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"> <StackPanel Grid.Column="0">
<TextBlock Style="{StaticResource MaterialDesignTextBlock}">Check for updates</TextBlock> <TextBlock Style="{StaticResource MaterialDesignTextBlock}">
Check for updates
</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap"> <TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap">
If enabled, we'll check for updates on startup and periodically while running. If enabled, we'll check for updates on startup and periodically while running.
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ToggleButton Style="{StaticResource MaterialDesignSwitchToggleButton}" IsChecked="{Binding CheckForUpdates}" /> <ToggleButton Style="{StaticResource MaterialDesignSwitchToggleButton}" IsChecked="{Binding UICheckForUpdates.Value}" />
</StackPanel> </StackPanel>
</Grid> </Grid>
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" /> <Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
@ -228,22 +247,24 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" VerticalAlignment="Center"> <StackPanel Grid.Column="0" VerticalAlignment="Center">
<TextBlock Style="{StaticResource MaterialDesignTextBlock}">Update</TextBlock> <TextBlock Style="{StaticResource MaterialDesignTextBlock}">
Update
</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}"> <TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}">
Use the button on the right to check for updates now. Use the button on the right to check for updates now.
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<Button Style="{StaticResource MaterialDesignOutlinedButton}" Command="{s:Action OfferUpdatesIfFound}" Width="150"> <Button Style="{StaticResource MaterialDesignOutlinedButton}" Command="{s:Action OfferUpdatesIfFound}" Width="150" Content="CHECK NOW" />
CHECK NOW
</Button>
</StackPanel> </StackPanel>
</Grid> </Grid>
</StackPanel> </StackPanel>
</materialDesign:Card> </materialDesign:Card>
<!-- Profile editor settings --> <!-- Profile editor settings -->
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" Margin="0 15">Profile editor</TextBlock> <TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" Margin="0 15">
<Run Text="Profile editor" />
</TextBlock>
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch" Margin="0,0,5,0"> <materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch" Margin="0,0,5,0">
<StackPanel Margin="15"> <StackPanel Margin="15">
<Grid> <Grid>
@ -256,16 +277,17 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"> <StackPanel Grid.Column="0">
<TextBlock Style="{StaticResource MaterialDesignTextBlock}">Show condition data model values</TextBlock> <TextBlock Style="{StaticResource MaterialDesignTextBlock}">
Show condition data model values
</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap"> <TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap">
While selecting a condition target, show the current values of the data model While selecting a condition target, show the current values of the data model.
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ToggleButton Style="{StaticResource MaterialDesignSwitchToggleButton}" IsChecked="{Binding ShowDataModelValues}" /> <ToggleButton Style="{StaticResource MaterialDesignSwitchToggleButton}" IsChecked="{Binding ProfileEditorShowDataModelValues.Value}" />
</StackPanel> </StackPanel>
</Grid> </Grid>
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" /> <Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
<Grid> <Grid>
@ -278,7 +300,9 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"> <StackPanel Grid.Column="0">
<TextBlock Style="{StaticResource MaterialDesignTextBlock}">Default brush</TextBlock> <TextBlock Style="{StaticResource MaterialDesignTextBlock}">
Default brush
</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap"> <TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap">
Sets the default brush that is applied to new layers Sets the default brush that is applied to new layers
</TextBlock> </TextBlock>
@ -290,18 +314,18 @@
materialDesign:ValidationAssist.UsePopup="True" materialDesign:ValidationAssist.UsePopup="True"
materialDesign:HintAssist.IsFloating="false" materialDesign:HintAssist.IsFloating="false"
HorizontalAlignment="Left" HorizontalAlignment="Left"
ItemsSource="{Binding Path=LayerBrushDescriptors}" ItemsSource="{Binding LayerBrushDescriptors}"
SelectedValue="{Binding Path=SelectedLayerBrushDescriptor}" SelectedValue="{Binding SelectedLayerBrushDescriptor}"
ItemTemplateSelector="{dataTemplateSelectors:ComboBoxTemplateSelector ItemTemplateSelector="{dataTemplateSelectors:ComboBoxTemplateSelector DropdownItemsTemplate={StaticResource ExtendedLayerBrushDescriptorTemplate}, SelectedItemTemplate={StaticResource SimpleLayerBrushDescriptorTemplate}}" />
SelectedItemTemplate={StaticResource SimpleLayerBrushDescriptorTemplate},
DropdownItemsTemplate={StaticResource ExtendedLayerBrushDescriptorTemplate}}" />
</StackPanel> </StackPanel>
</Grid> </Grid>
</StackPanel> </StackPanel>
</materialDesign:Card> </materialDesign:Card>
<!-- Rendering settings --> <!-- Rendering settings -->
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" Margin="0 15">Rendering</TextBlock> <TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" Margin="0 15">
Rendering
</TextBlock>
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch" Margin="0,0,5,0"> <materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch" Margin="0,0,5,0">
<StackPanel Margin="15"> <StackPanel Margin="15">
<Grid> <Grid>
@ -314,15 +338,17 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"> <StackPanel Grid.Column="0">
<TextBlock Style="{StaticResource MaterialDesignTextBlock}">Preferred render method</TextBlock> <TextBlock Style="{StaticResource MaterialDesignTextBlock}">
Preferred render method
</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap"> <TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap">
Software-based rendering is done purely on the CPU while Vulkan uses GPU-acceleration Software-based rendering is done purely on the CPU while Vulkan uses GPU-acceleration.
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ComboBox Style="{StaticResource MaterialDesignFilledComboBox}" <ComboBox Style="{StaticResource MaterialDesignFilledComboBox}"
Width="100" Width="100"
SelectedItem="{Binding PreferredGraphicsContext}" SelectedItem="{Binding CorePreferredGraphicsContext.Value}"
materialDesign:HintAssist.IsFloating="false"> materialDesign:HintAssist.IsFloating="false">
<system:String>Software</system:String> <system:String>Software</system:String>
<system:String>Vulkan</system:String> <system:String>Vulkan</system:String>
@ -341,7 +367,9 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"> <StackPanel Grid.Column="0">
<TextBlock Style="{StaticResource MaterialDesignTextBlock}">Render scale</TextBlock> <TextBlock Style="{StaticResource MaterialDesignTextBlock}">
Render scale
</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap"> <TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap">
Sets the resolution Artemis renders at, higher scale means more CPU-usage, especially on large surfaces. Sets the resolution Artemis renders at, higher scale means more CPU-usage, especially on large surfaces.
</TextBlock> </TextBlock>
@ -367,9 +395,12 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<StackPanel Grid.Column="0"> <StackPanel Grid.Column="0">
<TextBlock Style="{StaticResource MaterialDesignTextBlock}">Target framerate</TextBlock> <TextBlock Style="{StaticResource MaterialDesignTextBlock}">
Target frame rate
</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap"> <TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" TextWrapping="Wrap">
Sets the FPS Artemis tries to render at, higher FPS means more CPU-usage but smoother animations. Sets the FPS Artemis tries to render at, higher FPS means more CPU-usage but smoother animations. <LineBreak/>
The options past 45 FPS are mostly useless unless you are using a custom device.
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
@ -386,7 +417,9 @@
<!-- Tools --> <!-- Tools -->
<TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" Margin="0 15">Tools</TextBlock> <TextBlock Style="{StaticResource MaterialDesignHeadline5TextBlock}" Margin="0 15">
Tools
</TextBlock>
<materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch" Margin="0,0,5,0"> <materialDesign:Card materialDesign:ShadowAssist.ShadowDepth="Depth1" VerticalAlignment="Stretch" Margin="0,0,5,0">
<StackPanel Margin="15"> <StackPanel Margin="15">
<Grid> <Grid>
@ -399,15 +432,15 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" VerticalAlignment="Center"> <StackPanel Grid.Column="0" VerticalAlignment="Center">
<TextBlock Style="{StaticResource MaterialDesignTextBlock}">Setup wizard</TextBlock> <TextBlock Style="{StaticResource MaterialDesignTextBlock}">
<Run Text="Setup wizard" />
</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}"> <TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}">
Opens the startup wizard usually shown when Artemis first starts. <Run Text="Opens the startup wizard usually shown when Artemis first starts." />
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<Button Style="{StaticResource MaterialDesignOutlinedButton}" Command="{s:Action ShowSetupWizard}" Width="150"> <Button Style="{StaticResource MaterialDesignOutlinedButton}" Command="{s:Action ShowSetupWizard}" Width="150" Content="SHOW WIZARD" />
SHOW WIZARD
</Button>
</StackPanel> </StackPanel>
</Grid> </Grid>
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" /> <Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
@ -422,15 +455,15 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" VerticalAlignment="Center"> <StackPanel Grid.Column="0" VerticalAlignment="Center">
<TextBlock Style="{StaticResource MaterialDesignTextBlock}">Debugger</TextBlock> <TextBlock Style="{StaticResource MaterialDesignTextBlock}">
Debugger
</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}"> <TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}">
Use the debugger to see the raw image Artemis is rendering on the surface. Use the debugger to see the raw image Artemis is rendering on the surface.
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<Button Style="{StaticResource MaterialDesignOutlinedButton}" Command="{s:Action ShowDebugger}" Width="150"> <Button Style="{StaticResource MaterialDesignOutlinedButton}" Command="{s:Action ShowDebugger}" Width="150" Content="SHOW DEBUGGER" />
SHOW DEBUGGER
</Button>
</StackPanel> </StackPanel>
</Grid> </Grid>
<Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" /> <Separator Style="{StaticResource MaterialDesignSeparator}" Margin="-15 5" />
@ -445,15 +478,15 @@
<ColumnDefinition Width="Auto" /> <ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions> </Grid.ColumnDefinitions>
<StackPanel Grid.Column="0" VerticalAlignment="Center"> <StackPanel Grid.Column="0" VerticalAlignment="Center">
<TextBlock Style="{StaticResource MaterialDesignTextBlock}">Application files</TextBlock> <TextBlock Style="{StaticResource MaterialDesignTextBlock}">
Application files
</TextBlock>
<TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}"> <TextBlock Style="{StaticResource MaterialDesignTextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}">
Opens the directory where application files like plugins and settings are stored. Opens the directory where application files like plugins and settings are stored.
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<Button Style="{StaticResource MaterialDesignOutlinedButton}" Command="{s:Action ShowDataFolder}" Width="150"> <Button Style="{StaticResource MaterialDesignOutlinedButton}" Command="{s:Action ShowDataFolder}" Width="150" Content="SHOW APP FILES" />
SHOW APP FILES
</Button>
</StackPanel> </StackPanel>
</Grid> </Grid>
</StackPanel> </StackPanel>

View File

@ -30,8 +30,6 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
private readonly IUpdateService _updateService; private readonly IUpdateService _updateService;
private readonly IWindowManager _windowManager; private readonly IWindowManager _windowManager;
private bool _canOfferUpdatesIfFound = true; private bool _canOfferUpdatesIfFound = true;
private List<Tuple<string, double>> _renderScales;
private List<Tuple<string, int>> _targetFrameRates;
public GeneralSettingsTabViewModel( public GeneralSettingsTabViewModel(
IKernel kernel, IKernel kernel,
@ -41,9 +39,8 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
ISettingsService settingsService, ISettingsService settingsService,
IUpdateService updateService, IUpdateService updateService,
IPluginManagementService pluginManagementService, IPluginManagementService pluginManagementService,
IMessageService messageService,
IRegistrationService registrationService, IRegistrationService registrationService,
ICoreService coreService IMessageService messageService
) )
{ {
DisplayName = "GENERAL"; DisplayName = "GENERAL";
@ -54,38 +51,34 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
_debugService = debugService; _debugService = debugService;
_settingsService = settingsService; _settingsService = settingsService;
_updateService = updateService; _updateService = updateService;
_messageService = messageService;
_registrationService = registrationService; _registrationService = registrationService;
_messageService = messageService;
LogLevels = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(LogEventLevel))); LogLevels = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(LogEventLevel)));
ColorSchemes = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(ApplicationColorScheme))); ColorSchemes = new BindableCollection<ValueDescription>(EnumUtilities.GetAllValuesAndDescriptions(typeof(ApplicationColorScheme)));
RenderScales = new List<Tuple<string, double>> RenderScales = new BindableCollection<Tuple<string, double>>
{ {
new("25%", 0.25), new("25%", 0.25),
new("50%", 0.5), new("50%", 0.5),
new("100%", 1), new("100%", 1)
};
TargetFrameRates = new BindableCollection<Tuple<string, int>>
{
new("10 FPS", 10),
new("20 FPS", 20),
new("30 FPS", 30),
new("45 FPS", 45),
new("60 FPS (lol)", 60),
new("144 FPS (omegalol)", 144)
}; };
TargetFrameRates = new List<Tuple<string, int>>();
for (int i = 10; i <= 30; i += 5)
TargetFrameRates.Add(new Tuple<string, int>(i + " FPS", i));
if (coreService.StartupArguments.Contains("--pcmr"))
{
TargetFrameRates.Add(new Tuple<string, int>("60 FPS (lol)", 60));
TargetFrameRates.Add(new Tuple<string, int>("144 FPS (omegalol)", 144));
}
List<LayerBrushProvider> layerBrushProviders = pluginManagementService.GetFeaturesOfType<LayerBrushProvider>(); List<LayerBrushProvider> layerBrushProviders = pluginManagementService.GetFeaturesOfType<LayerBrushProvider>();
LayerBrushDescriptors = new BindableCollection<LayerBrushDescriptor>(layerBrushProviders.SelectMany(l => l.LayerBrushDescriptors)); LayerBrushDescriptors = new BindableCollection<LayerBrushDescriptor>(layerBrushProviders.SelectMany(l => l.LayerBrushDescriptors));
_defaultLayerBrushDescriptor = _settingsService.GetSetting("ProfileEditor.DefaultLayerBrushDescriptor", new LayerBrushReference _defaultLayerBrushDescriptor = _settingsService.GetSetting("ProfileEditor.DefaultLayerBrushDescriptor", new LayerBrushReference
{ {
LayerBrushProviderId = "Artemis.Plugins.LayerBrushes.Color.ColorBrushProvider-92a9d6ba", LayerBrushProviderId = "Artemis.Plugins.LayerBrushes.Color.ColorBrushProvider-92a9d6ba",
BrushType = "SolidBrush" BrushType = "SolidBrush"
}); });
WebServerPortSetting = _settingsService.GetSetting("WebServer.Port", 9696);
WebServerPortSetting.AutoSave = true;
} }
public BindableCollection<LayerBrushDescriptor> LayerBrushDescriptors { get; } public BindableCollection<LayerBrushDescriptor> LayerBrushDescriptors { get; }
@ -93,148 +86,87 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
public LayerBrushDescriptor SelectedLayerBrushDescriptor public LayerBrushDescriptor SelectedLayerBrushDescriptor
{ {
get => LayerBrushDescriptors.FirstOrDefault(d => d.MatchesLayerBrushReference(_defaultLayerBrushDescriptor.Value)); get => LayerBrushDescriptors.FirstOrDefault(d => d.MatchesLayerBrushReference(_defaultLayerBrushDescriptor.Value));
set set => _defaultLayerBrushDescriptor.Value = new LayerBrushReference(value);
{
_defaultLayerBrushDescriptor.Value = new LayerBrushReference(value);
_defaultLayerBrushDescriptor.Save();
}
} }
public BindableCollection<ValueDescription> LogLevels { get; } public BindableCollection<ValueDescription> LogLevels { get; }
public BindableCollection<ValueDescription> ColorSchemes { get; } public BindableCollection<ValueDescription> ColorSchemes { get; }
public BindableCollection<Tuple<string, double>> RenderScales { get; }
public List<Tuple<string, int>> TargetFrameRates public BindableCollection<Tuple<string, int>> TargetFrameRates { get; }
{
get => _targetFrameRates;
set => SetAndNotify(ref _targetFrameRates, value);
}
public List<Tuple<string, double>> RenderScales
{
get => _renderScales;
set => SetAndNotify(ref _renderScales, value);
}
public bool StartWithWindows
{
get => _settingsService.GetSetting("UI.AutoRun", false).Value;
set
{
_settingsService.GetSetting("UI.AutoRun", false).Value = value;
_settingsService.GetSetting("UI.AutoRun", false).Save();
NotifyOfPropertyChange(nameof(StartWithWindows));
Task.Run(() => ApplyAutorun(false));
}
}
public int AutoRunDelay
{
get => _settingsService.GetSetting("UI.AutoRunDelay", 15).Value;
set
{
_settingsService.GetSetting("UI.AutoRunDelay", 15).Value = value;
_settingsService.GetSetting("UI.AutoRunDelay", 15).Save();
NotifyOfPropertyChange(nameof(AutoRunDelay));
Task.Run(() => ApplyAutorun(true));
}
}
public bool StartMinimized
{
get => !_settingsService.GetSetting("UI.ShowOnStartup", true).Value;
set
{
_settingsService.GetSetting("UI.ShowOnStartup", true).Value = !value;
_settingsService.GetSetting("UI.ShowOnStartup", true).Save();
NotifyOfPropertyChange(nameof(StartMinimized));
}
}
public bool CheckForUpdates
{
get => _settingsService.GetSetting("UI.CheckForUpdates", true).Value;
set
{
_settingsService.GetSetting("UI.CheckForUpdates", true).Value = value;
_settingsService.GetSetting("UI.CheckForUpdates", true).Save();
NotifyOfPropertyChange(nameof(CheckForUpdates));
}
}
public bool ShowDataModelValues
{
get => _settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false).Value;
set
{
_settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false).Value = value;
_settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false).Save();
}
}
public Tuple<string, double> SelectedRenderScale public Tuple<string, double> SelectedRenderScale
{ {
get => RenderScales.FirstOrDefault(s => Math.Abs(s.Item2 - RenderScale) < 0.01); get => RenderScales.FirstOrDefault(s => Math.Abs(s.Item2 - CoreRenderScale.Value) < 0.01);
set => RenderScale = value.Item2; set => CoreRenderScale.Value = value.Item2;
} }
public Tuple<string, int> SelectedTargetFrameRate public Tuple<string, int> SelectedTargetFrameRate
{ {
get => TargetFrameRates.FirstOrDefault(t => Math.Abs(t.Item2 - TargetFrameRate) < 0.01); get => TargetFrameRates.FirstOrDefault(s => s.Item2 == CoreTargetFrameRate.Value);
set => TargetFrameRate = value.Item2; set => CoreTargetFrameRate.Value = value.Item2;
} }
public LogEventLevel SelectedLogLevel 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);
private void UIAutoRunOnSettingChanged(object sender, EventArgs e)
{ {
get => _settingsService.GetSetting("Core.LoggingLevel", LogEventLevel.Information).Value; Task.Run(() => ApplyAutorun(false));
set }
private void UIAutoRunDelayOnSettingChanged(object sender, EventArgs e)
{
Task.Run(() => ApplyAutorun(true));
}
private void CorePreferredGraphicsContextOnSettingChanged(object sender, EventArgs e)
{
_registrationService.ApplyPreferredGraphicsContext();
}
private void ApplyAutorun(bool recreate)
{
if (!UIAutoRun.Value)
UIShowOnStartup.Value = true;
// Remove the old auto-run method of placing a shortcut in shell:startup
string autoRunFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Startup), "Artemis.lnk");
if (File.Exists(autoRunFile))
File.Delete(autoRunFile);
if (Constants.BuildInfo.IsLocalBuild)
return;
// Create or remove the task if necessary
try
{ {
_settingsService.GetSetting("Core.LoggingLevel", LogEventLevel.Information).Value = value; bool taskCreated = false;
_settingsService.GetSetting("Core.LoggingLevel", LogEventLevel.Information).Save(); if (!recreate)
taskCreated = SettingsUtilities.IsAutoRunTaskCreated();
if (UIAutoRun.Value && !taskCreated)
SettingsUtilities.CreateAutoRunTask(TimeSpan.FromSeconds(UIAutoRunDelay.Value));
else if (!UIAutoRun.Value && taskCreated)
SettingsUtilities.RemoveAutoRunTask();
}
catch (Exception e)
{
Execute.PostToUIThread(() => _dialogService.ShowExceptionDialog("An exception occured while trying to apply the auto run setting", e));
throw;
} }
} }
public ApplicationColorScheme SelectedColorScheme #region View methods
{
get => _settingsService.GetSetting("UI.ColorScheme", ApplicationColorScheme.Automatic).Value;
set
{
_settingsService.GetSetting("UI.ColorScheme", ApplicationColorScheme.Automatic).Value = value;
_settingsService.GetSetting("UI.ColorScheme", ApplicationColorScheme.Automatic).Save();
}
}
public string PreferredGraphicsContext
{
get => _settingsService.GetSetting("Core.PreferredGraphicsContext", "Vulkan").Value;
set
{
_settingsService.GetSetting("Core.PreferredGraphicsContext", "Vulkan").Value = value;
_settingsService.GetSetting("Core.PreferredGraphicsContext", "Vulkan").Save();
_registrationService.ApplyPreferredGraphicsContext();
}
}
public double RenderScale
{
get => _settingsService.GetSetting("Core.RenderScale", 0.25).Value;
set
{
_settingsService.GetSetting("Core.RenderScale", 0.25).Value = value;
_settingsService.GetSetting("Core.RenderScale", 0.25).Save();
}
}
public int TargetFrameRate
{
get => _settingsService.GetSetting("Core.TargetFrameRate", 25).Value;
set
{
_settingsService.GetSetting("Core.TargetFrameRate", 25).Value = value;
_settingsService.GetSetting("Core.TargetFrameRate", 25).Save();
}
}
public PluginSetting<int> WebServerPortSetting { get; }
public bool CanOfferUpdatesIfFound public bool CanOfferUpdatesIfFound
{ {
@ -298,44 +230,32 @@ namespace Artemis.UI.Screens.Settings.Tabs.General
} }
} }
#endregion
#region Overrides of Screen
protected override void OnInitialActivate() protected override void OnInitialActivate()
{ {
Task.Run(() => ApplyAutorun(false)); Task.Run(() => ApplyAutorun(false));
UIAutoRun.SettingChanged += UIAutoRunOnSettingChanged;
UIAutoRunDelay.SettingChanged += UIAutoRunDelayOnSettingChanged;
CorePreferredGraphicsContext.SettingChanged += CorePreferredGraphicsContextOnSettingChanged;
base.OnInitialActivate(); base.OnInitialActivate();
} }
private void ApplyAutorun(bool recreate) protected override void OnClose()
{ {
if (!StartWithWindows) UIAutoRun.SettingChanged -= UIAutoRunOnSettingChanged;
StartMinimized = false; UIAutoRunDelay.SettingChanged -= UIAutoRunDelayOnSettingChanged;
CorePreferredGraphicsContext.SettingChanged -= CorePreferredGraphicsContextOnSettingChanged;
// Remove the old auto-run method of placing a shortcut in shell:startup _settingsService.SaveAllSettings();
string autoRunFile = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Startup), "Artemis.lnk"); base.OnClose();
if (File.Exists(autoRunFile))
File.Delete(autoRunFile);
if (Constants.BuildInfo.IsLocalBuild)
return;
// Create or remove the task if necessary
try
{
bool taskCreated = false;
if (!recreate) taskCreated = SettingsUtilities.IsAutoRunTaskCreated();
if (StartWithWindows && !taskCreated)
SettingsUtilities.CreateAutoRunTask(TimeSpan.FromSeconds(AutoRunDelay));
else if (!StartWithWindows && taskCreated)
SettingsUtilities.RemoveAutoRunTask();
}
catch (Exception e)
{
Execute.PostToUIThread(() => _dialogService.ShowExceptionDialog("An exception occured while trying to apply the auto run setting", e));
throw;
}
} }
}
#endregion
}
public enum ApplicationColorScheme public enum ApplicationColorScheme
{ {

View File

@ -4,16 +4,12 @@ using System.Windows;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Media; using System.Windows.Media;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using Artemis.Core;
using Artemis.Core.Services; using Artemis.Core.Services;
using Artemis.UI.Events; using Artemis.UI.Events;
using Artemis.UI.Screens.Settings.Tabs.General;
using Artemis.UI.Screens.Splash; using Artemis.UI.Screens.Splash;
using Artemis.UI.Services; using Artemis.UI.Services;
using Artemis.UI.Shared.Services; using Artemis.UI.Shared.Services;
using Artemis.UI.Utilities;
using Hardcodet.Wpf.TaskbarNotification; using Hardcodet.Wpf.TaskbarNotification;
using MaterialDesignThemes.Wpf;
using Ninject; using Ninject;
using Stylet; using Stylet;
@ -21,11 +17,10 @@ namespace Artemis.UI.Screens
{ {
public class TrayViewModel : Screen, IMainWindowProvider public class TrayViewModel : Screen, IMainWindowProvider
{ {
private readonly PluginSetting<ApplicationColorScheme> _colorScheme;
private readonly IDebugService _debugService; private readonly IDebugService _debugService;
private readonly IEventAggregator _eventAggregator; private readonly IEventAggregator _eventAggregator;
private readonly IKernel _kernel; private readonly IKernel _kernel;
private readonly ThemeWatcher _themeWatcher; private readonly IThemeService _themeService;
private readonly IWindowManager _windowManager; private readonly IWindowManager _windowManager;
private ImageSource _icon; private ImageSource _icon;
private bool _openingMainWindow; private bool _openingMainWindow;
@ -40,24 +35,20 @@ namespace Artemis.UI.Screens
IEventAggregator eventAggregator, IEventAggregator eventAggregator,
ICoreService coreService, ICoreService coreService,
IDebugService debugService, IDebugService debugService,
ISettingsService settingsService) ISettingsService settingsService,
IThemeService themeService)
{ {
_kernel = kernel; _kernel = kernel;
_windowManager = windowManager; _windowManager = windowManager;
_eventAggregator = eventAggregator; _eventAggregator = eventAggregator;
_debugService = debugService; _debugService = debugService;
_themeService = themeService;
Core.Utilities.ShutdownRequested += UtilitiesOnShutdownRequested; Core.Utilities.ShutdownRequested += UtilitiesOnShutdownRequested;
Core.Utilities.RestartRequested += UtilitiesOnShutdownRequested; Core.Utilities.RestartRequested += UtilitiesOnShutdownRequested;
_themeWatcher = new ThemeWatcher(); _themeService.SystemThemeChanged += ThemeServiceOnSystemThemeChanged;
_colorScheme = settingsService.GetSetting("UI.ColorScheme", ApplicationColorScheme.Automatic); ApplyTrayIconTheme(_themeService.GetSystemTheme());
_colorScheme.SettingChanged += ColorSchemeOnSettingChanged;
_themeWatcher.SystemThemeChanged += _themeWatcher_SystemThemeChanged;
_themeWatcher.AppsThemeChanged += _themeWatcher_AppsThemeChanged;
ApplyColorSchemeSetting();
ApplyTrayIconTheme(_themeWatcher.GetSystemTheme());
windowService.ConfigureMainWindowProvider(this); windowService.ConfigureMainWindowProvider(this);
bool autoRunning = Bootstrapper.StartupArguments.Contains("--autorun"); bool autoRunning = Bootstrapper.StartupArguments.Contains("--autorun");
@ -191,60 +182,21 @@ namespace Artemis.UI.Screens
#region Theme #region Theme
private void ApplyColorSchemeSetting() private void ApplyTrayIconTheme(IThemeService.WindowsTheme theme)
{
if (_colorScheme.Value == ApplicationColorScheme.Automatic)
ApplyUITheme(_themeWatcher.GetAppsTheme());
else
ChangeMaterialColors(_colorScheme.Value);
}
private void ApplyUITheme(ThemeWatcher.WindowsTheme theme)
{
if (_colorScheme.Value != ApplicationColorScheme.Automatic)
return;
if (theme == ThemeWatcher.WindowsTheme.Dark)
ChangeMaterialColors(ApplicationColorScheme.Dark);
else
ChangeMaterialColors(ApplicationColorScheme.Light);
}
private void ApplyTrayIconTheme(ThemeWatcher.WindowsTheme theme)
{ {
Execute.PostToUIThread(() => Execute.PostToUIThread(() =>
{ {
Icon = theme == ThemeWatcher.WindowsTheme.Dark Icon = theme == IThemeService.WindowsTheme.Dark
? new BitmapImage(new Uri("pack://application:,,,/Artemis.UI;component/Resources/Images/Logo/bow-white.ico")) ? new BitmapImage(new Uri("pack://application:,,,/Artemis.UI;component/Resources/Images/Logo/bow-white.ico"))
: new BitmapImage(new Uri("pack://application:,,,/Artemis.UI;component/Resources/Images/Logo/bow-black.ico")); : new BitmapImage(new Uri("pack://application:,,,/Artemis.UI;component/Resources/Images/Logo/bow-black.ico"));
}); });
} }
private void ChangeMaterialColors(ApplicationColorScheme colorScheme) private void ThemeServiceOnSystemThemeChanged(object sender, WindowsThemeEventArgs e)
{
PaletteHelper paletteHelper = new();
ITheme theme = paletteHelper.GetTheme();
theme.SetBaseTheme(colorScheme == ApplicationColorScheme.Dark ? Theme.Dark : Theme.Light);
paletteHelper.SetTheme(theme);
MaterialDesignExtensions.Themes.PaletteHelper extensionsPaletteHelper = new();
extensionsPaletteHelper.SetLightDark(colorScheme == ApplicationColorScheme.Dark);
}
private void _themeWatcher_AppsThemeChanged(object sender, WindowsThemeEventArgs e)
{
ApplyUITheme(e.Theme);
}
private void _themeWatcher_SystemThemeChanged(object sender, WindowsThemeEventArgs e)
{ {
ApplyTrayIconTheme(e.Theme); ApplyTrayIconTheme(e.Theme);
} }
private void ColorSchemeOnSettingChanged(object sender, EventArgs e)
{
ApplyColorSchemeSetting();
}
#endregion #endregion
#region Implementation of IMainWindowProvider #region Implementation of IMainWindowProvider

View File

@ -26,6 +26,7 @@ namespace Artemis.UI.Services
private readonly IWebServerService _webServerService; private readonly IWebServerService _webServerService;
private readonly IRgbService _rgbService; private readonly IRgbService _rgbService;
private readonly ISettingsService _settingsService; private readonly ISettingsService _settingsService;
private readonly IThemeService _themeService;
private bool _registeredBuiltInDataModelDisplays; private bool _registeredBuiltInDataModelDisplays;
private bool _registeredBuiltInDataModelInputs; private bool _registeredBuiltInDataModelInputs;
private bool _registeredBuiltInPropertyEditors; private bool _registeredBuiltInPropertyEditors;
@ -40,7 +41,8 @@ namespace Artemis.UI.Services
IMessageService messageService, IMessageService messageService,
IWebServerService webServerService, IWebServerService webServerService,
IRgbService rgbService, IRgbService rgbService,
ISettingsService settingsService) ISettingsService settingsService,
IThemeService themeService)
{ {
_logger = logger; _logger = logger;
_coreService = coreService; _coreService = coreService;
@ -52,6 +54,7 @@ namespace Artemis.UI.Services
_webServerService = webServerService; _webServerService = webServerService;
_rgbService = rgbService; _rgbService = rgbService;
_settingsService = settingsService; _settingsService = settingsService;
_themeService = themeService;
LoadPluginModules(); LoadPluginModules();
pluginManagementService.PluginEnabling += PluginServiceOnPluginEnabling; pluginManagementService.PluginEnabling += PluginServiceOnPluginEnabling;
@ -105,7 +108,7 @@ namespace Artemis.UI.Services
public void RegisterProviders() public void RegisterProviders()
{ {
_inputService.AddInputProvider(new NativeWindowInputProvider(_logger, _inputService)); _inputService.AddInputProvider(new NativeWindowInputProvider(_logger, _inputService));
_messageService.SetNotificationProvider(new ToastNotificationProvider()); _messageService.SetNotificationProvider(new ToastNotificationProvider(_themeService));
} }
public void RegisterControllers() public void RegisterControllers()

View File

@ -0,0 +1,176 @@
using System;
using System.Globalization;
using System.Management;
using System.Security.Principal;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Events;
using Artemis.UI.Screens.Settings.Tabs.General;
using MaterialDesignThemes.Wpf;
using Microsoft.Win32;
namespace Artemis.UI.Services
{
public class ThemeService : IThemeService
{
private readonly PluginSetting<ApplicationColorScheme> _colorScheme;
private const string RegistryKeyPath = @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize";
private const string AppsThemeRegistryValueName = "AppsUseLightTheme";
private const string SystemThemeRegistryValueName = "SystemUsesLightTheme";
public ThemeService(ISettingsService settingsService)
{
WatchTheme();
_colorScheme = settingsService.GetSetting("UI.ColorScheme", ApplicationColorScheme.Automatic);
_colorScheme.SettingChanged += ColorSchemeOnSettingChanged;
ApplyColorSchemeSetting();
AppsThemeChanged += OnAppsThemeChanged;
}
public IThemeService.WindowsTheme GetAppsTheme()
{
return GetTheme(AppsThemeRegistryValueName);
}
public IThemeService.WindowsTheme GetSystemTheme()
{
return GetTheme(SystemThemeRegistryValueName);
}
private void ApplyColorSchemeSetting()
{
if (_colorScheme.Value == ApplicationColorScheme.Automatic)
ApplyUITheme(GetAppsTheme());
else
ChangeMaterialColors(_colorScheme.Value);
}
private void ChangeMaterialColors(ApplicationColorScheme colorScheme)
{
PaletteHelper paletteHelper = new();
ITheme theme = paletteHelper.GetTheme();
theme.SetBaseTheme(colorScheme == ApplicationColorScheme.Dark ? Theme.Dark : Theme.Light);
paletteHelper.SetTheme(theme);
MaterialDesignExtensions.Themes.PaletteHelper extensionsPaletteHelper = new();
extensionsPaletteHelper.SetLightDark(colorScheme == ApplicationColorScheme.Dark);
}
private void ApplyUITheme(IThemeService.WindowsTheme theme)
{
if (_colorScheme.Value != ApplicationColorScheme.Automatic)
return;
if (theme == IThemeService.WindowsTheme.Dark)
ChangeMaterialColors(ApplicationColorScheme.Dark);
else
ChangeMaterialColors(ApplicationColorScheme.Light);
}
private void WatchTheme()
{
WindowsIdentity currentUser = WindowsIdentity.GetCurrent();
string appsThemequery = string.Format(
CultureInfo.InvariantCulture,
@"SELECT * FROM RegistryValueChangeEvent WHERE Hive = 'HKEY_USERS' AND KeyPath = '{0}\\{1}' AND ValueName = '{2}'",
currentUser.User.Value,
RegistryKeyPath.Replace(@"\", @"\\"),
AppsThemeRegistryValueName);
string systemThemequery = string.Format(
CultureInfo.InvariantCulture,
@"SELECT * FROM RegistryValueChangeEvent WHERE Hive = 'HKEY_USERS' AND KeyPath = '{0}\\{1}' AND ValueName = '{2}'",
currentUser.User.Value,
RegistryKeyPath.Replace(@"\", @"\\"),
SystemThemeRegistryValueName);
try
{
// For Apps theme
ManagementEventWatcher appsThemWatcher = new(appsThemequery);
appsThemWatcher.EventArrived += (_, _) =>
{
IThemeService.WindowsTheme newWindowsTheme = GetAppsTheme();
OnAppsThemeChanged(new WindowsThemeEventArgs(newWindowsTheme));
};
// Start listening for apps theme events
appsThemWatcher.Start();
// For System theme
ManagementEventWatcher systemThemWatcher = new(systemThemequery);
systemThemWatcher.EventArrived += (_, _) =>
{
IThemeService.WindowsTheme newWindowsTheme = GetSystemTheme();
OnSystemThemeChanged(new WindowsThemeEventArgs(newWindowsTheme));
};
// Start listening for system theme events
systemThemWatcher.Start();
}
catch (Exception)
{
// This can fail on Windows 7
}
}
private IThemeService.WindowsTheme GetTheme(string themeKeyName)
{
using RegistryKey key = Registry.CurrentUser.OpenSubKey(RegistryKeyPath);
object registryValueObject = key?.GetValue(themeKeyName);
if (registryValueObject == null) return IThemeService.WindowsTheme.Light;
int registryValue = (int) registryValueObject;
return registryValue > 0 ? IThemeService.WindowsTheme.Light : IThemeService.WindowsTheme.Dark;
}
#region Events
public event EventHandler<WindowsThemeEventArgs> AppsThemeChanged;
public event EventHandler<WindowsThemeEventArgs> SystemThemeChanged;
protected virtual void OnAppsThemeChanged(WindowsThemeEventArgs e)
{
AppsThemeChanged?.Invoke(this, e);
}
protected virtual void OnSystemThemeChanged(WindowsThemeEventArgs e)
{
SystemThemeChanged?.Invoke(this, e);
}
#endregion
#region Event handlers
private void ColorSchemeOnSettingChanged(object sender, EventArgs e)
{
ApplyColorSchemeSetting();
}
private void OnAppsThemeChanged(object sender, WindowsThemeEventArgs e)
{
ApplyUITheme(e.Theme);
}
#endregion
}
public interface IThemeService : IArtemisUIService
{
WindowsTheme GetAppsTheme();
WindowsTheme GetSystemTheme();
event EventHandler<WindowsThemeEventArgs> AppsThemeChanged;
event EventHandler<WindowsThemeEventArgs> SystemThemeChanged;
enum WindowsTheme
{
Light,
Dark
}
}
}

View File

@ -1,112 +0,0 @@
using System;
using System.Globalization;
using System.Management;
using System.Security.Principal;
using Artemis.UI.Events;
using Microsoft.Win32;
namespace Artemis.UI.Utilities
{
public class ThemeWatcher
{
private const string RegistryKeyPath = @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize";
private const string appsThemeRegistryValueName = "AppsUseLightTheme";
private const string systemThemeRegistryValueName = "SystemUsesLightTheme";
public ThemeWatcher()
{
WatchTheme();
}
public void WatchTheme()
{
WindowsIdentity currentUser = WindowsIdentity.GetCurrent();
string appsThemequery = string.Format(
CultureInfo.InvariantCulture,
@"SELECT * FROM RegistryValueChangeEvent WHERE Hive = 'HKEY_USERS' AND KeyPath = '{0}\\{1}' AND ValueName = '{2}'",
currentUser.User.Value,
RegistryKeyPath.Replace(@"\", @"\\"),
appsThemeRegistryValueName);
string systemThemequery = string.Format(
CultureInfo.InvariantCulture,
@"SELECT * FROM RegistryValueChangeEvent WHERE Hive = 'HKEY_USERS' AND KeyPath = '{0}\\{1}' AND ValueName = '{2}'",
currentUser.User.Value,
RegistryKeyPath.Replace(@"\", @"\\"),
systemThemeRegistryValueName);
try
{
// For Apps theme
ManagementEventWatcher appsThemWatcher = new(appsThemequery);
appsThemWatcher.EventArrived += (_, _) =>
{
WindowsTheme newWindowsTheme = GetAppsTheme();
OnAppsThemeChanged(new WindowsThemeEventArgs(newWindowsTheme));
};
// Start listening for apps theme events
appsThemWatcher.Start();
// For System theme
ManagementEventWatcher systemThemWatcher = new(systemThemequery);
systemThemWatcher.EventArrived += (_, _) =>
{
WindowsTheme newWindowsTheme = GetSystemTheme();
OnSystemThemeChanged(new WindowsThemeEventArgs(newWindowsTheme));
};
// Start listening for system theme events
systemThemWatcher.Start();
}
catch (Exception)
{
// This can fail on Windows 7
}
}
private WindowsTheme GetTheme(string themeKeyName)
{
using (RegistryKey key = Registry.CurrentUser.OpenSubKey(RegistryKeyPath))
{
object registryValueObject = key?.GetValue(themeKeyName);
if (registryValueObject == null) return WindowsTheme.Light;
int registryValue = (int)registryValueObject;
return registryValue > 0 ? WindowsTheme.Light : WindowsTheme.Dark;
}
}
public WindowsTheme GetAppsTheme()
{
return GetTheme(appsThemeRegistryValueName);
}
public WindowsTheme GetSystemTheme()
{
return GetTheme(systemThemeRegistryValueName);
}
public event EventHandler<WindowsThemeEventArgs> AppsThemeChanged;
public event EventHandler<WindowsThemeEventArgs> SystemThemeChanged;
protected virtual void OnAppsThemeChanged(WindowsThemeEventArgs e)
{
AppsThemeChanged?.Invoke(this, e);
}
protected virtual void OnSystemThemeChanged(WindowsThemeEventArgs e)
{
SystemThemeChanged?.Invoke(this, e);
}
public enum WindowsTheme
{
Light,
Dark
}
}
}