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

Core - Moved startup arguments from CoreService to Constants

Web server - Added setting to disable the web server
Web server - Added --disable-webserver startup argument to disable the web server
UI - Fixed Artemis not bringing existing instances to foreground if already running
This commit is contained in:
Robert 2022-08-26 20:32:36 +02:00
parent 87b87a9145
commit 928d9711af
14 changed files with 516 additions and 455 deletions

View File

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO; using System.IO;
using System.Reflection; using System.Reflection;
using Artemis.Core.JsonConverters; using Artemis.Core.JsonConverters;
@ -90,6 +91,11 @@ public static class Constants
/// </summary> /// </summary>
public static readonly Plugin CorePlugin = new(CorePluginInfo, new DirectoryInfo(ApplicationFolder), null); public static readonly Plugin CorePlugin = new(CorePluginInfo, new DirectoryInfo(ApplicationFolder), null);
/// <summary>
/// Gets the startup arguments provided to the application
/// </summary>
public static ReadOnlyCollection<string> StartupArguments { get; set; } = null!;
internal static readonly CorePluginFeature CorePluginFeature = new() {Plugin = CorePlugin, Profiler = CorePlugin.GetProfiler("Feature - Core")}; internal static readonly CorePluginFeature CorePluginFeature = new() {Plugin = CorePlugin, Profiler = CorePlugin.GetProfiler("Feature - Core")};
internal static readonly EffectPlaceholderPlugin EffectPlaceholderPlugin = new() {Plugin = CorePlugin, Profiler = CorePlugin.GetProfiler("Feature - Effect Placeholder")}; internal static readonly EffectPlaceholderPlugin EffectPlaceholderPlugin = new() {Plugin = CorePlugin, Profiler = CorePlugin.GetProfiler("Feature - Effect Placeholder")};

View File

@ -58,7 +58,6 @@ internal class CoreService : ICoreService
_scriptingService = scriptingService; _scriptingService = scriptingService;
_loggingLevel = settingsService.GetSetting("Core.LoggingLevel", LogEventLevel.Debug); _loggingLevel = settingsService.GetSetting("Core.LoggingLevel", LogEventLevel.Debug);
_frameStopWatch = new Stopwatch(); _frameStopWatch = new Stopwatch();
StartupArguments = new List<string>();
_rgbService.Surface.Updating += SurfaceOnUpdating; _rgbService.Surface.Updating += SurfaceOnUpdating;
_loggingLevel.SettingChanged += (sender, args) => ApplyLoggingLevel(); _loggingLevel.SettingChanged += (sender, args) => ApplyLoggingLevel();
@ -78,7 +77,7 @@ internal class CoreService : ICoreService
private void ApplyLoggingLevel() private void ApplyLoggingLevel()
{ {
string? argument = StartupArguments.FirstOrDefault(a => a.StartsWith("--logging")); string? argument = Constants.StartupArguments.FirstOrDefault(a => a.StartsWith("--logging"));
if (argument != null) if (argument != null)
{ {
// Parse the provided log level // Parse the provided log level
@ -194,7 +193,6 @@ internal class CoreService : ICoreService
public int FrameRate { get; private set; } public int FrameRate { get; private set; }
public TimeSpan FrameTime { get; private set; } public TimeSpan FrameTime { get; private set; }
public bool ProfileRenderingDisabled { get; set; } public bool ProfileRenderingDisabled { get; set; }
public List<string> StartupArguments { get; set; }
public bool IsElevated { get; set; } public bool IsElevated { get; set; }
public void Dispose() public void Dispose()
@ -217,7 +215,7 @@ internal class CoreService : ICoreService
Constants.BuildInfo.BuildNumber, Constants.BuildInfo.BuildNumber,
Constants.BuildInfo.SourceBranch Constants.BuildInfo.SourceBranch
); );
_logger.Information("Startup arguments: {args}", StartupArguments); _logger.Information("Startup arguments: {args}", Constants.StartupArguments);
_logger.Information("Elevated permissions: {perms}", IsElevated); _logger.Information("Elevated permissions: {perms}", IsElevated);
_logger.Information("Stopwatch high resolution: {perms}", Stopwatch.IsHighResolution); _logger.Information("Stopwatch high resolution: {perms}", Stopwatch.IsHighResolution);
@ -230,9 +228,9 @@ internal class CoreService : ICoreService
// Initialize the services // Initialize the services
_pluginManagementService.CopyBuiltInPlugins(); _pluginManagementService.CopyBuiltInPlugins();
_pluginManagementService.LoadPlugins(StartupArguments, IsElevated); _pluginManagementService.LoadPlugins(IsElevated);
_rgbService.ApplyPreferredGraphicsContext(StartupArguments.Contains("--force-software-render")); _rgbService.ApplyPreferredGraphicsContext(Constants.StartupArguments.Contains("--force-software-render"));
_rgbService.SetRenderPaused(false); _rgbService.SetRenderPaused(false);
OnInitialized(); OnInitialized();
} }

View File

@ -27,12 +27,7 @@ public interface ICoreService : IArtemisService, IDisposable
/// Gets or sets whether profiles are rendered each frame by calling their Render method /// Gets or sets whether profiles are rendered each frame by calling their Render method
/// </summary> /// </summary>
bool ProfileRenderingDisabled { get; set; } bool ProfileRenderingDisabled { get; set; }
/// <summary>
/// Gets or sets a list of startup arguments
/// </summary>
List<string> StartupArguments { get; set; }
/// <summary> /// <summary>
/// Gets a boolean indicating whether Artemis is running in an elevated environment (admin permissions) /// Gets a boolean indicating whether Artemis is running in an elevated environment (admin permissions)
/// </summary> /// </summary>

View File

@ -26,7 +26,7 @@ public interface IPluginManagementService : IArtemisService, IDisposable
/// <summary> /// <summary>
/// Loads all installed plugins. If plugins already loaded this will reload them all /// Loads all installed plugins. If plugins already loaded this will reload them all
/// </summary> /// </summary>
void LoadPlugins(List<string> startupArguments, bool isElevated); void LoadPlugins(bool isElevated);
/// <summary> /// <summary>
/// Unloads all installed plugins. /// Unloads all installed plugins.

View File

@ -203,17 +203,17 @@ internal class PluginManagementService : IPluginManagementService
#region Plugins #region Plugins
public void LoadPlugins(List<string> startupArguments, bool isElevated) public void LoadPlugins(bool isElevated)
{ {
if (startupArguments.Contains("--no-plugins")) if (Constants.StartupArguments.Contains("--no-plugins"))
{ {
_logger.Warning("Artemis launched with --no-plugins, skipping the loading of plugins"); _logger.Warning("Artemis launched with --no-plugins, skipping the loading of plugins");
return; return;
} }
bool ignorePluginLock = startupArguments.Contains("--ignore-plugin-lock"); bool ignorePluginLock = Constants.StartupArguments.Contains("--ignore-plugin-lock");
bool stayElevated = startupArguments.Contains("--force-elevation"); bool stayElevated = Constants.StartupArguments.Contains("--force-elevation");
bool droppedAdmin = startupArguments.Contains("--dropped-admin"); bool droppedAdmin = Constants.StartupArguments.Contains("--dropped-admin");
if (LoadingPlugins) if (LoadingPlugins)
throw new ArtemisCoreException("Cannot load plugins while a previous load hasn't been completed yet."); throw new ArtemisCoreException("Cannot load plugins while a previous load hasn't been completed yet.");

View File

@ -3,6 +3,7 @@ using System.Collections.Generic;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text; using System.Text;
using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using Artemis.Core.Modules; using Artemis.Core.Modules;
using EmbedIO; using EmbedIO;
@ -17,15 +18,19 @@ internal class WebServerService : IWebServerService, IDisposable
private readonly List<WebApiControllerRegistration> _controllers; private readonly List<WebApiControllerRegistration> _controllers;
private readonly ILogger _logger; private readonly ILogger _logger;
private readonly List<WebModuleRegistration> _modules; private readonly List<WebModuleRegistration> _modules;
private readonly PluginSetting<bool> _webServerEnabledSetting;
private readonly PluginSetting<int> _webServerPortSetting; private readonly PluginSetting<int> _webServerPortSetting;
private CancellationTokenSource? _cts;
public WebServerService(ILogger logger, ISettingsService settingsService, IPluginManagementService pluginManagementService) public WebServerService(ILogger logger, ICoreService coreService, ISettingsService settingsService, IPluginManagementService pluginManagementService)
{ {
_logger = logger; _logger = logger;
_controllers = new List<WebApiControllerRegistration>(); _controllers = new List<WebApiControllerRegistration>();
_modules = new List<WebModuleRegistration>(); _modules = new List<WebModuleRegistration>();
_webServerEnabledSetting = settingsService.GetSetting("WebServer.Enabled", true);
_webServerPortSetting = settingsService.GetSetting("WebServer.Port", 9696); _webServerPortSetting = settingsService.GetSetting("WebServer.Port", 9696);
_webServerEnabledSetting.SettingChanged += WebServerEnabledSettingOnSettingChanged;
_webServerPortSetting.SettingChanged += WebServerPortSettingOnSettingChanged; _webServerPortSetting.SettingChanged += WebServerPortSettingOnSettingChanged;
pluginManagementService.PluginFeatureDisabled += PluginManagementServiceOnPluginFeatureDisabled; pluginManagementService.PluginFeatureDisabled += PluginManagementServiceOnPluginFeatureDisabled;
@ -33,9 +38,9 @@ internal class WebServerService : IWebServerService, IDisposable
StartWebServer(); StartWebServer();
} }
protected virtual void OnWebServerStarting() private void WebServerEnabledSettingOnSettingChanged(object? sender, EventArgs e)
{ {
WebServerStarting?.Invoke(this, EventArgs.Empty); StartWebServer();
} }
private void WebServerPortSettingOnSettingChanged(object? sender, EventArgs e) private void WebServerPortSettingOnSettingChanged(object? sender, EventArgs e)
@ -72,14 +77,23 @@ internal class WebServerService : IWebServerService, IDisposable
public WebServer? Server { get; private set; } public WebServer? Server { get; private set; }
public PluginsModule PluginsModule { get; } public PluginsModule PluginsModule { get; }
public event EventHandler? WebServerStarting;
#region Web server managament #region Web server managament
private WebServer CreateWebServer() private WebServer CreateWebServer()
{ {
Server?.Dispose(); if (Server != null)
Server = null; {
if (_cts != null)
{
_cts.Cancel();
_cts = null;
}
Server.Dispose();
OnWebServerStopped();
Server = null;
}
WebApiModule apiModule = new("/", JsonNetSerializer); WebApiModule apiModule = new("/", JsonNetSerializer);
PluginsModule.ServerUrl = $"http://localhost:{_webServerPortSetting.Value}/"; PluginsModule.ServerUrl = $"http://localhost:{_webServerPortSetting.Value}/";
@ -112,8 +126,20 @@ internal class WebServerService : IWebServerService, IDisposable
private void StartWebServer() private void StartWebServer()
{ {
Server = CreateWebServer(); Server = CreateWebServer();
if (!_webServerEnabledSetting.Value)
return;
if (Constants.StartupArguments.Contains("--disable-webserver"))
{
_logger.Warning("Artemis launched with --disable-webserver, not enabling the webserver");
return;
}
OnWebServerStarting(); OnWebServerStarting();
Server.Start(); _cts = new CancellationTokenSource();
Server.Start(_cts.Token);
OnWebServerStarted();
} }
#endregion #endregion
@ -276,4 +302,27 @@ internal class WebServerService : IWebServerService, IDisposable
} }
#endregion #endregion
#region Events
protected virtual void OnWebServerStopped()
{
WebServerStopped?.Invoke(this, EventArgs.Empty);
}
protected virtual void OnWebServerStarting()
{
WebServerStarting?.Invoke(this, EventArgs.Empty);
}
protected virtual void OnWebServerStarted()
{
WebServerStarted?.Invoke(this, EventArgs.Empty);
}
public event EventHandler? WebServerStopped;
public event EventHandler? WebServerStarting;
public event EventHandler? WebServerStarted;
#endregion
} }

View File

@ -1,3 +1,11 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Threading;
using Artemis.Core;
using Artemis.Core.Services; using Artemis.Core.Services;
using Artemis.UI.Windows.Ninject; using Artemis.UI.Windows.Ninject;
using Artemis.UI.Windows.Providers.Input; using Artemis.UI.Windows.Providers.Input;
@ -13,14 +21,23 @@ namespace Artemis.UI.Windows;
public class App : Application public class App : Application
{ {
private StandardKernel? _kernel;
private bool _shutDown;
// ReSharper disable NotAccessedField.Local // ReSharper disable NotAccessedField.Local
private ApplicationStateManager? _applicationStateManager; private ApplicationStateManager? _applicationStateManager;
private Mutex? _artemisMutex;
// ReSharper restore NotAccessedField.Local // ReSharper restore NotAccessedField.Local
private StandardKernel? _kernel;
public override void Initialize() public override void Initialize()
{ {
// If Artemis is already running, bring it to foreground and stop this process
if (FocusExistingInstance())
{
_shutDown = true;
Environment.Exit(1);
}
_kernel = ArtemisBootstrapper.Bootstrap(this, new WindowsModule()); _kernel = ArtemisBootstrapper.Bootstrap(this, new WindowsModule());
Program.CreateLogger(_kernel); Program.CreateLogger(_kernel);
RxApp.MainThreadScheduler = AvaloniaScheduler.Instance; RxApp.MainThreadScheduler = AvaloniaScheduler.Instance;
@ -29,7 +46,7 @@ public class App : Application
public override void OnFrameworkInitializationCompleted() public override void OnFrameworkInitializationCompleted()
{ {
if (ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop || Design.IsDesignMode) if (ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop || Design.IsDesignMode || _shutDown)
return; return;
ArtemisBootstrapper.Initialize(); ArtemisBootstrapper.Initialize();
@ -42,4 +59,55 @@ public class App : Application
IInputService inputService = standardKernel.Get<IInputService>(); IInputService inputService = standardKernel.Get<IInputService>();
inputService.AddInputProvider(standardKernel.Get<WindowsInputProvider>()); inputService.AddInputProvider(standardKernel.Get<WindowsInputProvider>());
} }
private bool FocusExistingInstance()
{
_artemisMutex = new Mutex(true, "Artemis-3c24b502-64e6-4587-84bf-9072970e535f", out bool createdNew);
return !createdNew && RemoteFocus();
}
private bool RemoteFocus()
{
// At this point we cannot read the database yet to retrieve the web server port.
// Instead use the method external applications should use as well.
if (!File.Exists(Path.Combine(Constants.DataFolder, "webserver.txt")))
{
KillOtherInstances();
return false;
}
string url = File.ReadAllText(Path.Combine(Constants.DataFolder, "webserver.txt"));
using HttpClient client = new();
try
{
CancellationTokenSource cts = new();
cts.CancelAfter(2000);
HttpResponseMessage httpResponseMessage = client.Send(new HttpRequestMessage(HttpMethod.Post, url + "remote/bring-to-foreground"), cts.Token);
httpResponseMessage.EnsureSuccessStatusCode();
return true;
}
catch (Exception)
{
KillOtherInstances();
return false;
}
}
private void KillOtherInstances()
{
// Kill everything else heh
List<Process> processes = Process.GetProcessesByName("Artemis.UI.Windows").Where(p => p.Id != Process.GetCurrentProcess().Id).ToList();
foreach (Process process in processes)
{
try
{
process.Kill(true);
}
catch (Exception)
{
// ignored
}
}
}
} }

View File

@ -3,12 +3,9 @@ using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Net.Http;
using System.Security.Principal; using System.Security.Principal;
using System.Threading;
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Services; using Artemis.Core.Services;
using Artemis.UI.Shared.Services;
using Artemis.UI.Windows.Utilities; using Artemis.UI.Windows.Utilities;
using Avalonia; using Avalonia;
using Avalonia.Controls.ApplicationLifetimes; using Avalonia.Controls.ApplicationLifetimes;
@ -19,14 +16,8 @@ namespace Artemis.UI.Windows;
public class ApplicationStateManager public class ApplicationStateManager
{ {
private readonly IWindowService _windowService;
// ReSharper disable once NotAccessedField.Local - Kept in scope to ensure it does not get released
private Mutex? _artemisMutex;
public ApplicationStateManager(IKernel kernel, string[] startupArguments) public ApplicationStateManager(IKernel kernel, string[] startupArguments)
{ {
_windowService = kernel.Get<IWindowService>();
StartupArguments = startupArguments; StartupArguments = startupArguments;
IsElevated = new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator); IsElevated = new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
@ -51,72 +42,6 @@ public class ApplicationStateManager
public string[] StartupArguments { get; } public string[] StartupArguments { get; }
public bool IsElevated { get; } public bool IsElevated { get; }
public bool FocusExistingInstance()
{
_artemisMutex = new Mutex(true, "Artemis-3c24b502-64e6-4587-84bf-9072970e535f", out bool createdNew);
if (createdNew)
return false;
return RemoteFocus();
}
public void DisplayException(Exception e)
{
try
{
_windowService.ShowExceptionDialog("An unhandled exception occured", e);
}
catch
{
// ignored, we tried
}
}
private bool RemoteFocus()
{
// At this point we cannot read the database yet to retrieve the web server port.
// Instead use the method external applications should use as well.
if (!File.Exists(Path.Combine(Constants.DataFolder, "webserver.txt")))
{
KillOtherInstances();
return false;
}
string url = File.ReadAllText(Path.Combine(Constants.DataFolder, "webserver.txt"));
using HttpClient client = new();
try
{
CancellationTokenSource cts = new();
cts.CancelAfter(2000);
HttpResponseMessage httpResponseMessage = client.Send(new HttpRequestMessage(HttpMethod.Post, url + "remote/bring-to-foreground"), cts.Token);
httpResponseMessage.EnsureSuccessStatusCode();
return true;
}
catch (Exception)
{
KillOtherInstances();
return false;
}
}
private void KillOtherInstances()
{
// Kill everything else heh
List<Process> processes = Process.GetProcessesByName("Artemis.UI.Windows").Where(p => p.Id != Process.GetCurrentProcess().Id).ToList();
foreach (Process process in processes)
{
try
{
process.Kill(true);
}
catch (Exception)
{
// ignored
}
}
}
private void UtilitiesOnRestartRequested(object? sender, RestartEventArgs e) private void UtilitiesOnRestartRequested(object? sender, RestartEventArgs e)
{ {
List<string> argsList = new(); List<string> argsList = new();

View File

@ -1,4 +1,7 @@
using System; using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive; using System.Reactive;
using Artemis.Core; using Artemis.Core;
using Artemis.Core.Ninject; using Artemis.Core.Ninject;
@ -52,6 +55,8 @@ public static class ArtemisBootstrapper
if (_application.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop) if (_application.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop)
return; return;
Constants.StartupArguments = new ReadOnlyCollection<string>(new List<string>(desktop.Args));
// Don't shut down when the last window closes, we might still be active in the tray // Don't shut down when the last window closes, we might still be active in the tray
desktop.ShutdownMode = ShutdownMode.OnExplicitShutdown; desktop.ShutdownMode = ShutdownMode.OnExplicitShutdown;
// Create the root view model that drives the UI // Create the root view model that drives the UI

View File

@ -47,12 +47,12 @@ public class MainWindow : ReactiveCoreWindow<RootViewModel>
private void OnActivated(object? sender, EventArgs e) private void OnActivated(object? sender, EventArgs e)
{ {
ViewModel.Focused(); ViewModel?.Focused();
} }
private void OnDeactivated(object? sender, EventArgs e) private void OnDeactivated(object? sender, EventArgs e)
{ {
ViewModel.Unfocused(); ViewModel?.Unfocused();
} }
private void InitializeComponent() private void InitializeComponent()

View File

@ -54,8 +54,7 @@ public class RootViewModel : ActivatableViewModelBase, IScreen, IMainWindowProvi
_defaultTitleBarViewModel = defaultTitleBarViewModel; _defaultTitleBarViewModel = defaultTitleBarViewModel;
_sidebarVmFactory = sidebarVmFactory; _sidebarVmFactory = sidebarVmFactory;
_lifeTime = (IClassicDesktopStyleApplicationLifetime) Application.Current!.ApplicationLifetime!; _lifeTime = (IClassicDesktopStyleApplicationLifetime) Application.Current!.ApplicationLifetime!;
coreService.StartupArguments = _lifeTime.Args.ToList();
mainWindowService.ConfigureMainWindowProvider(this); mainWindowService.ConfigureMainWindowProvider(this);
DisplayAccordingToSettings(); DisplayAccordingToSettings();
@ -99,8 +98,8 @@ public class RootViewModel : ActivatableViewModelBase, IScreen, IMainWindowProvi
private void DisplayAccordingToSettings() private void DisplayAccordingToSettings()
{ {
bool autoRunning = _coreService.StartupArguments.Contains("--autorun"); bool autoRunning = Constants.StartupArguments.Contains("--autorun");
bool minimized = _coreService.StartupArguments.Contains("--minimized"); bool minimized = Constants.StartupArguments.Contains("--minimized");
bool showOnAutoRun = _settingsService.GetSetting("UI.ShowOnStartup", true).Value; bool showOnAutoRun = _settingsService.GetSetting("UI.ShowOnStartup", true).Value;
if ((autoRunning && !showOnAutoRun) || minimized) if ((autoRunning && !showOnAutoRun) || minimized)

View File

@ -13,364 +13,379 @@
x:DataType="settings:GeneralTabViewModel"> x:DataType="settings:GeneralTabViewModel">
<ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto"> <ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
<StackPanel Margin="15" MaxWidth="1000"> <StackPanel Margin="15" MaxWidth="1000">
<!-- General settings --> <!-- General settings -->
<TextBlock Classes="h4" Margin="0 15"> <TextBlock Classes="h4" Margin="0 15">
General General
</TextBlock> </TextBlock>
<Border Classes="card" VerticalAlignment="Stretch" Margin="0,0,5,0"> <Border Classes="card" VerticalAlignment="Stretch" Margin="0,0,5,0">
<StackPanel> <StackPanel>
<StackPanel IsVisible="{CompiledBinding IsAutoRunSupported}"> <StackPanel IsVisible="{CompiledBinding IsAutoRunSupported}">
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto"> <Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0"> <StackPanel Grid.Column="0">
<TextBlock>Auto-run on startup</TextBlock> <TextBlock>Auto-run on startup</TextBlock>
</StackPanel> </StackPanel>
<ToggleSwitch Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" IsChecked="{CompiledBinding UIAutoRun.Value}" MinWidth="0" Margin="0 -10"/> <ToggleSwitch Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" IsChecked="{CompiledBinding UIAutoRun.Value}" MinWidth="0" Margin="0 -10" OnContent="Yes"
</Grid> OffContent="No" />
<Separator Classes="card-separator" /> </Grid>
<Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto"> <Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0"> <StackPanel Grid.Column="0">
<TextBlock>Hide window on auto-run</TextBlock> <TextBlock>Hide window on auto-run</TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ToggleSwitch IsChecked="{CompiledBinding !UIShowOnStartup.Value}" IsEnabled="{CompiledBinding UIAutoRun.Value}" MinWidth="0" Margin="0 -10"/> <ToggleSwitch IsChecked="{CompiledBinding !UIShowOnStartup.Value}" IsEnabled="{CompiledBinding UIAutoRun.Value}" MinWidth="0" Margin="0 -10" OnContent="Yes"
</StackPanel> OffContent="No" />
</Grid> </StackPanel>
<Separator Classes="card-separator" /> </Grid>
<Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto"> <Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0"> <StackPanel Grid.Column="0">
<TextBlock>Startup delay</TextBlock> <TextBlock>Startup delay</TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap"> <TextBlock Classes="subtitle" TextWrapping="Wrap">
Set the amount of seconds to wait before auto-running Artemis. Set the amount of seconds to wait before auto-running Artemis.
</TextBlock> </TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap"> <TextBlock Classes="subtitle" TextWrapping="Wrap">
If some devices don't work because Artemis starts before the manufacturer's software, try increasing this value. 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" Orientation="Horizontal"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center" Orientation="Horizontal">
<controls:NumberBox IsEnabled="{CompiledBinding UIAutoRun.Value}" Width="120"> <controls:NumberBox IsEnabled="{CompiledBinding UIAutoRun.Value}" Width="120">
<Interaction.Behaviors> <Interaction.Behaviors>
<behaviors:LostFocusNumberBoxBindingBehavior Value="{CompiledBinding UIAutoRunDelay.Value}"/> <behaviors:LostFocusNumberBoxBindingBehavior Value="{CompiledBinding UIAutoRunDelay.Value}" />
</Interaction.Behaviors> </Interaction.Behaviors>
</controls:NumberBox> </controls:NumberBox>
<TextBlock VerticalAlignment="Center" TextAlignment="Right" Width="30">sec</TextBlock> <TextBlock VerticalAlignment="Center" TextAlignment="Right" Width="30">sec</TextBlock>
</StackPanel> </StackPanel>
</Grid> </Grid>
<Separator Classes="card-separator" /> <Separator Classes="card-separator" />
</StackPanel> </StackPanel>
<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">
<shared:EnumComboBox Width="150" Value="{CompiledBinding CoreLoggingLevel.Value}" />
</StackPanel>
</Grid>
<Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto"> <Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" VerticalAlignment="Center"> <StackPanel Grid.Column="0">
<TextBlock> <TextBlock>
Logs Log level
</TextBlock> </TextBlock>
<TextBlock Classes="subtitle"> <TextBlock Classes="subtitle" TextWrapping="Wrap">
Opens the directory where logs are stored. Sets the logging level, a higher logging level will result in more log files.
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<Button Command="{CompiledBinding ShowLogs}" Width="150" Content="Show logs" /> <shared:EnumComboBox Width="150" Value="{CompiledBinding CoreLoggingLevel.Value}" />
</StackPanel> </StackPanel>
</Grid> </Grid>
</StackPanel> <Separator Classes="card-separator" />
</Border>
<!-- Web server settings --> <Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<TextBlock Classes="h4" Margin="0 15"> <StackPanel Grid.Column="0" VerticalAlignment="Center">
Web server <TextBlock>
</TextBlock> Logs
<Border Classes="card" VerticalAlignment="Stretch" Margin="0,0,5,0"> </TextBlock>
<StackPanel> <TextBlock Classes="subtitle">
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto"> Opens the directory where logs are stored.
<StackPanel Grid.Column="0"> </TextBlock>
<TextBlock> </StackPanel>
Web server port <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
</TextBlock> <Button Command="{CompiledBinding ShowLogs}" Width="150" Content="Show logs" />
<TextBlock Classes="subtitle" TextWrapping="Wrap"> </StackPanel>
Artemis runs a local web server that can be used to externally interact with the application. </Grid>
</TextBlock> </StackPanel>
<TextBlock Classes="subtitle" TextWrapping="Wrap"> </Border>
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">
<controls:NumberBox Width="150">
<Interaction.Behaviors>
<behaviors:LostFocusNumberBoxBindingBehavior Value="{CompiledBinding WebServerPort.Value}"/>
</Interaction.Behaviors>
</controls:NumberBox>
</StackPanel>
</Grid>
</StackPanel>
</Border>
<!-- Update settings --> <!-- Web server settings -->
<StackPanel IsVisible="{CompiledBinding IsUpdatingSupported}"> <TextBlock Classes="h4" Margin="0 15">
<TextBlock Classes="h4" Margin="0 15"> Web server
Updating </TextBlock>
</TextBlock> <Border Classes="card" VerticalAlignment="Stretch" Margin="0,0,5,0">
<Border Classes="card" VerticalAlignment="Stretch" Margin="0,0,5,0"> <StackPanel>
<StackPanel> <Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto"> <StackPanel Grid.Column="0">
<StackPanel Grid.Column="0"> <TextBlock>Enable web server</TextBlock>
<TextBlock> <TextBlock Classes="subtitle" TextWrapping="Wrap">
Check for updates Artemis runs a local web server that can be used to externally interact with the application.
</TextBlock> </TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap"> <TextBlock Classes="subtitle" TextWrapping="Wrap">
If enabled, we'll check for updates on startup and periodically while running. 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">
<ToggleSwitch IsChecked="{CompiledBinding UICheckForUpdates.Value}" MinWidth="0" /> <ToggleSwitch IsChecked="{CompiledBinding WebServerEnabled.Value}" OnContent="Yes" OffContent="No" MinWidth="0" Margin="0 -10" />
</StackPanel> </StackPanel>
</Grid> </Grid>
<Separator Classes="card-separator" /> <Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0">
<TextBlock>
Auto-install updates
</TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap">
If enabled, new updates will automatically be installed.
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ToggleSwitch IsEnabled="{CompiledBinding UICheckForUpdates.Value}" IsChecked="{CompiledBinding UIAutoUpdate.Value}" MinWidth="0" />
</StackPanel>
</Grid>
<Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto"> <Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" VerticalAlignment="Center"> <StackPanel Grid.Column="0">
<TextBlock> <TextBlock>
Update Web server port
</TextBlock> </TextBlock>
<TextBlock Classes="subtitle"> <TextBlock Classes="subtitle" TextWrapping="Wrap">
Use the button on the right to check for updates now. If the webserver does not work you can try changing the port to one that is available.
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<Button Command="{CompiledBinding CheckForUpdate}" Width="150" Content="Check now" /> <controls:NumberBox Width="150">
</StackPanel> <Interaction.Behaviors>
</Grid> <behaviors:LostFocusNumberBoxBindingBehavior Value="{CompiledBinding WebServerPort.Value}" />
</StackPanel> </Interaction.Behaviors>
</Border> </controls:NumberBox>
</StackPanel> </StackPanel>
</Grid>
</StackPanel>
</Border>
<!-- Profile editor settings --> <!-- Update settings -->
<TextBlock Classes="h4" Margin="0 15"> <StackPanel IsVisible="{CompiledBinding IsUpdatingSupported}">
Profile editor <TextBlock Classes="h4" Margin="0 15">
</TextBlock> Updating
<Border Classes="card" VerticalAlignment="Stretch" Margin="0,0,5,0"> </TextBlock>
<StackPanel> <Border Classes="card" VerticalAlignment="Stretch" Margin="0,0,5,0">
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto"> <StackPanel>
<StackPanel Grid.Column="0"> <Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<TextBlock> <StackPanel Grid.Column="0">
Show condition data model values <TextBlock>
</TextBlock> Check for updates
<TextBlock Classes="subtitle" TextWrapping="Wrap"> </TextBlock>
While selecting a condition target, show the current values of the data model. <TextBlock Classes="subtitle" TextWrapping="Wrap">
</TextBlock> If enabled, we'll check for updates on startup and periodically while running.
</StackPanel> </TextBlock>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> </StackPanel>
<ToggleSwitch IsChecked="{CompiledBinding ProfileEditorShowDataModelValues.Value}" MinWidth="0" /> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
</StackPanel> <ToggleSwitch IsChecked="{CompiledBinding UICheckForUpdates.Value}" MinWidth="0" OnContent="Yes" OffContent="No" />
</Grid> </StackPanel>
<Separator Classes="card-separator" /> </Grid>
<Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto"> <Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0"> <StackPanel Grid.Column="0">
<TextBlock> <TextBlock>
Default brush Auto-install updates
</TextBlock> </TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap"> <TextBlock Classes="subtitle" TextWrapping="Wrap">
Sets the default brush that is applied to new layers If enabled, new updates will automatically be installed.
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<StackPanel.Styles> <ToggleSwitch IsEnabled="{CompiledBinding UICheckForUpdates.Value}" IsChecked="{CompiledBinding UIAutoUpdate.Value}" MinWidth="0" OnContent="Yes" OffContent="No" />
<Style Selector="ComboBox.brush /template/ ContentControl#ContentPresenter"> </StackPanel>
<Setter Property="ContentTemplate"> </Grid>
<Setter.Value> <Separator Classes="card-separator" />
<DataTemplate DataType="{x:Type layerBrushes:LayerBrushDescriptor}">
<StackPanel Orientation="Horizontal">
<avalonia:MaterialIcon Kind="{CompiledBinding Icon}" Height="20" Width="20" VerticalAlignment="Center" Margin="0 0 5 0"/>
<TextBlock Text="{CompiledBinding DisplayName}" VerticalAlignment="Center" />
</StackPanel>
</DataTemplate>
</Setter.Value>
</Setter>
</Style>
</StackPanel.Styles>
<ComboBox Classes="brush"
Width="200"
HorizontalAlignment="Left"
Items="{CompiledBinding LayerBrushDescriptors}"
SelectedItem="{CompiledBinding SelectedLayerBrushDescriptor}">
<ComboBox.ItemTemplate>
<DataTemplate DataType="{x:Type layerBrushes:LayerBrushDescriptor}">
<Grid ColumnDefinitions="30,*" RowDefinitions="Auto,Auto">
<avalonia:MaterialIcon Grid.Row="0"
Grid.RowSpan="2"
Kind="{CompiledBinding Icon}"
Height="20"
Width="20"
VerticalAlignment="Center"
HorizontalAlignment="Left" />
<TextBlock Grid.Row="0" Grid.Column="1" Text="{CompiledBinding DisplayName}" TextWrapping="Wrap" MaxWidth="350" />
<TextBlock Classes="subtitle" Grid.Row="1" Grid.Column="1" Text="{CompiledBinding Description}" TextWrapping="Wrap" MaxWidth="350" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</Grid>
</StackPanel>
</Border>
<!-- Rendering settings --> <Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<TextBlock Classes="h4" Margin="0 15"> <StackPanel Grid.Column="0" VerticalAlignment="Center">
Rendering <TextBlock>
</TextBlock> Update
<Border Classes="card" VerticalAlignment="Stretch" Margin="0,0,5,0"> </TextBlock>
<StackPanel> <TextBlock Classes="subtitle">
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto"> Use the button on the right to check for updates now.
<StackPanel Grid.Column="0"> </TextBlock>
<TextBlock> </StackPanel>
Preferred render method <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
</TextBlock> <Button Command="{CompiledBinding CheckForUpdate}" Width="150" Content="Check now" />
<TextBlock Classes="subtitle" TextWrapping="Wrap"> </StackPanel>
Software-based rendering is done purely on the CPU while Vulkan uses GPU-acceleration. </Grid>
</TextBlock> </StackPanel>
</StackPanel> </Border>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> </StackPanel>
<ComboBox Width="150"
SelectedItem="{CompiledBinding CorePreferredGraphicsContext.Value}"
Items="{CompiledBinding GraphicsContexts}"/>
</StackPanel>
</Grid>
<Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto"> <!-- Profile editor settings -->
<StackPanel Grid.Column="0"> <TextBlock Classes="h4" Margin="0 15">
<TextBlock> Profile editor
Render scale </TextBlock>
</TextBlock> <Border Classes="card" VerticalAlignment="Stretch" Margin="0,0,5,0">
<TextBlock Classes="subtitle" TextWrapping="Wrap"> <StackPanel>
Sets the resolution Artemis renders at, higher scale means more CPU-usage, especially on large surfaces. <Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
</TextBlock> <StackPanel Grid.Column="0">
</StackPanel> <TextBlock>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> Show condition data model values
<ComboBox Width="150" </TextBlock>
SelectedItem="{CompiledBinding SelectedRenderScale}" <TextBlock Classes="subtitle" TextWrapping="Wrap">
Items="{CompiledBinding RenderScales}"> While selecting a condition target, show the current values of the data model.
<ComboBox.ItemTemplate> </TextBlock>
<DataTemplate> </StackPanel>
<TextBlock Text="{CompiledBinding Display}" /> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
</DataTemplate> <ToggleSwitch IsChecked="{CompiledBinding ProfileEditorShowDataModelValues.Value}" MinWidth="0" OnContent="Yes" OffContent="No" />
</ComboBox.ItemTemplate> </StackPanel>
</ComboBox> </Grid>
</StackPanel> <Separator Classes="card-separator" />
</Grid>
<Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto"> <Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0"> <StackPanel Grid.Column="0">
<TextBlock> <TextBlock>
Target frame rate Default brush
</TextBlock> </TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap"> <TextBlock Classes="subtitle" TextWrapping="Wrap">
Sets the FPS Artemis tries to render at, higher FPS means more CPU-usage but smoother animations. Sets the default brush that is applied to new layers
</TextBlock> </TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap"> </StackPanel>
The options past 45 FPS are mostly useless unless you are using a custom device. <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
</TextBlock> <StackPanel.Styles>
</StackPanel> <Style Selector="ComboBox.brush /template/ ContentControl#ContentPresenter">
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <Setter Property="ContentTemplate">
<ComboBox Width="150" <Setter.Value>
SelectedItem="{CompiledBinding SelectedTargetFrameRate}" <DataTemplate DataType="{x:Type layerBrushes:LayerBrushDescriptor}">
Items="{CompiledBinding TargetFrameRates}"> <StackPanel Orientation="Horizontal">
<ComboBox.ItemTemplate> <avalonia:MaterialIcon Kind="{CompiledBinding Icon}" Height="20" Width="20" VerticalAlignment="Center" Margin="0 0 5 0" />
<DataTemplate> <TextBlock Text="{CompiledBinding DisplayName}" VerticalAlignment="Center" />
<TextBlock Text="{CompiledBinding Display}" /> </StackPanel>
</DataTemplate> </DataTemplate>
</ComboBox.ItemTemplate> </Setter.Value>
</ComboBox> </Setter>
</StackPanel> </Style>
</Grid> </StackPanel.Styles>
</StackPanel> <ComboBox Classes="brush"
</Border> Width="200"
HorizontalAlignment="Left"
Items="{CompiledBinding LayerBrushDescriptors}"
SelectedItem="{CompiledBinding SelectedLayerBrushDescriptor}">
<ComboBox.ItemTemplate>
<DataTemplate DataType="{x:Type layerBrushes:LayerBrushDescriptor}">
<Grid ColumnDefinitions="30,*" RowDefinitions="Auto,Auto">
<avalonia:MaterialIcon Grid.Row="0"
Grid.RowSpan="2"
Kind="{CompiledBinding Icon}"
Height="20"
Width="20"
VerticalAlignment="Center"
HorizontalAlignment="Left" />
<TextBlock Grid.Row="0" Grid.Column="1" Text="{CompiledBinding DisplayName}" TextWrapping="Wrap" MaxWidth="350" />
<TextBlock Classes="subtitle" Grid.Row="1" Grid.Column="1" Text="{CompiledBinding Description}" TextWrapping="Wrap" MaxWidth="350" />
</Grid>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</Grid>
</StackPanel>
</Border>
<!-- Tools --> <!-- Rendering settings -->
<TextBlock Classes="h4" Margin="0 15"> <TextBlock Classes="h4" Margin="0 15">
Tools Rendering
</TextBlock> </TextBlock>
<Border Classes="card" VerticalAlignment="Stretch" Margin="0,0,5,0"> <Border Classes="card" VerticalAlignment="Stretch" Margin="0,0,5,0">
<StackPanel> <StackPanel>
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto"> <Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" VerticalAlignment="Center"> <StackPanel Grid.Column="0">
<TextBlock> <TextBlock>
Setup wizard Preferred render method
</TextBlock> </TextBlock>
<TextBlock Classes="subtitle"> <TextBlock Classes="subtitle" TextWrapping="Wrap">
Opens the startup wizard usually shown when Artemis first starts. 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">
<Button Command="{CompiledBinding ShowSetupWizard}" Width="150" Content="Show wizard" /> <ComboBox Width="150"
</StackPanel> SelectedItem="{CompiledBinding CorePreferredGraphicsContext.Value}"
</Grid> Items="{CompiledBinding GraphicsContexts}" />
<Separator Classes="card-separator" /> </StackPanel>
</Grid>
<Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto"> <Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" VerticalAlignment="Center"> <StackPanel Grid.Column="0">
<TextBlock> <TextBlock>
Debugger Render scale
</TextBlock> </TextBlock>
<TextBlock Classes="subtitle"> <TextBlock Classes="subtitle" TextWrapping="Wrap">
Use the debugger to see the raw image Artemis is rendering on the surface. Sets the resolution Artemis renders at, higher scale means more CPU-usage, especially on large surfaces.
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<Button Command="{CompiledBinding ShowDebugger}" Width="150" Content="Show debugger" /> <ComboBox Width="150"
</StackPanel> SelectedItem="{CompiledBinding SelectedRenderScale}"
</Grid> Items="{CompiledBinding RenderScales}">
<Separator Classes="card-separator" /> <ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{CompiledBinding Display}" />
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
</Grid>
<Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto"> <Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0" VerticalAlignment="Center"> <StackPanel Grid.Column="0">
<TextBlock> <TextBlock>
Application files Target frame rate
</TextBlock> </TextBlock>
<TextBlock Classes="subtitle"> <TextBlock Classes="subtitle" TextWrapping="Wrap">
Opens the directory where application files like plugins and settings are stored. Sets the FPS Artemis tries to render at, higher FPS means more CPU-usage but smoother animations.
</TextBlock> </TextBlock>
</StackPanel> <TextBlock Classes="subtitle" TextWrapping="Wrap">
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> The options past 45 FPS are mostly useless unless you are using a custom device.
<Button Command="{CompiledBinding ShowDataFolder}" Width="150" Content="Show app files" /> </TextBlock>
</StackPanel> </StackPanel>
</Grid> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
</StackPanel> <ComboBox Width="150"
</Border> SelectedItem="{CompiledBinding SelectedTargetFrameRate}"
</StackPanel> Items="{CompiledBinding TargetFrameRates}">
</ScrollViewer> <ComboBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{CompiledBinding Display}" />
</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="{CompiledBinding 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="{CompiledBinding 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="{CompiledBinding ShowDataFolder}" Width="150" Content="Show app files" />
</StackPanel>
</Grid>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
</UserControl> </UserControl>

View File

@ -149,6 +149,7 @@ public class GeneralTabViewModel : ActivatableViewModelBase
public PluginSetting<string> CorePreferredGraphicsContext => _settingsService.GetSetting("Core.PreferredGraphicsContext", "Software"); public PluginSetting<string> CorePreferredGraphicsContext => _settingsService.GetSetting("Core.PreferredGraphicsContext", "Software");
public PluginSetting<double> CoreRenderScale => _settingsService.GetSetting("Core.RenderScale", 0.25); public PluginSetting<double> CoreRenderScale => _settingsService.GetSetting("Core.RenderScale", 0.25);
public PluginSetting<int> CoreTargetFrameRate => _settingsService.GetSetting("Core.TargetFrameRate", 30); public PluginSetting<int> CoreTargetFrameRate => _settingsService.GetSetting("Core.TargetFrameRate", 30);
public PluginSetting<bool> WebServerEnabled => _settingsService.GetSetting("WebServer.Enabled", true);
public PluginSetting<int> WebServerPort => _settingsService.GetSetting("WebServer.Port", 9696); public PluginSetting<int> WebServerPort => _settingsService.GetSetting("WebServer.Port", 9696);
private void ExecuteShowLogs() private void ExecuteShowLogs()

View File

@ -17,7 +17,7 @@ public class SaturateNode : Node
#region Constructors #region Constructors
public SaturateNode() public SaturateNode()
: base("Clamp", "Clamps the value to be in between 0 and 1") : base("Saturate", "Clamps the value to be in between 0 and 1")
{ {
Value = CreateInputPin<Numeric>(); Value = CreateInputPin<Numeric>();