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

@ -28,11 +28,6 @@ public interface ICoreService : IArtemisService, IDisposable
/// </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)
{
if (_cts != null)
{
_cts.Cancel();
_cts = null;
}
Server.Dispose();
OnWebServerStopped();
Server = null; 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

@ -55,7 +55,6 @@ public class RootViewModel : ActivatableViewModelBase, IScreen, IMainWindowProvi
_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

@ -25,7 +25,8 @@
<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"
OffContent="No" />
</Grid> </Grid>
<Separator Classes="card-separator" /> <Separator Classes="card-separator" />
@ -34,7 +35,8 @@
<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"
OffContent="No" />
</StackPanel> </StackPanel>
</Grid> </Grid>
<Separator Classes="card-separator" /> <Separator Classes="card-separator" />
@ -52,7 +54,7 @@
<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>
@ -100,9 +102,7 @@
<StackPanel> <StackPanel>
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto"> <Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0"> <StackPanel Grid.Column="0">
<TextBlock> <TextBlock>Enable web server</TextBlock>
Web server port
</TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap"> <TextBlock Classes="subtitle" TextWrapping="Wrap">
Artemis runs a local web server that can be used to externally interact with the application. Artemis runs a local web server that can be used to externally interact with the application.
</TextBlock> </TextBlock>
@ -110,10 +110,25 @@
This web server can only be accessed by applications running on your own computer, e.g. supported games. 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">
<ToggleSwitch IsChecked="{CompiledBinding WebServerEnabled.Value}" OnContent="Yes" OffContent="No" MinWidth="0" Margin="0 -10" />
</StackPanel>
</Grid>
<Separator Classes="card-separator" />
<Grid RowDefinitions="*,*" ColumnDefinitions="*,Auto">
<StackPanel Grid.Column="0">
<TextBlock>
Web server port
</TextBlock>
<TextBlock Classes="subtitle" TextWrapping="Wrap">
If the webserver does not work you can try changing the port to one that is available.
</TextBlock>
</StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<controls:NumberBox Width="150"> <controls:NumberBox Width="150">
<Interaction.Behaviors> <Interaction.Behaviors>
<behaviors:LostFocusNumberBoxBindingBehavior Value="{CompiledBinding WebServerPort.Value}"/> <behaviors:LostFocusNumberBoxBindingBehavior Value="{CompiledBinding WebServerPort.Value}" />
</Interaction.Behaviors> </Interaction.Behaviors>
</controls:NumberBox> </controls:NumberBox>
</StackPanel> </StackPanel>
@ -138,7 +153,7 @@
</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 UICheckForUpdates.Value}" MinWidth="0" OnContent="Yes" OffContent="No" />
</StackPanel> </StackPanel>
</Grid> </Grid>
<Separator Classes="card-separator" /> <Separator Classes="card-separator" />
@ -153,7 +168,7 @@
</TextBlock> </TextBlock>
</StackPanel> </StackPanel>
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ToggleSwitch IsEnabled="{CompiledBinding UICheckForUpdates.Value}" IsChecked="{CompiledBinding UIAutoUpdate.Value}" MinWidth="0" /> <ToggleSwitch IsEnabled="{CompiledBinding UICheckForUpdates.Value}" IsChecked="{CompiledBinding UIAutoUpdate.Value}" MinWidth="0" OnContent="Yes" OffContent="No" />
</StackPanel> </StackPanel>
</Grid> </Grid>
<Separator Classes="card-separator" /> <Separator Classes="card-separator" />
@ -191,7 +206,7 @@
</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 ProfileEditorShowDataModelValues.Value}" MinWidth="0" /> <ToggleSwitch IsChecked="{CompiledBinding ProfileEditorShowDataModelValues.Value}" MinWidth="0" OnContent="Yes" OffContent="No" />
</StackPanel> </StackPanel>
</Grid> </Grid>
<Separator Classes="card-separator" /> <Separator Classes="card-separator" />
@ -212,7 +227,7 @@
<Setter.Value> <Setter.Value>
<DataTemplate DataType="{x:Type layerBrushes:LayerBrushDescriptor}"> <DataTemplate DataType="{x:Type layerBrushes:LayerBrushDescriptor}">
<StackPanel Orientation="Horizontal"> <StackPanel Orientation="Horizontal">
<avalonia:MaterialIcon Kind="{CompiledBinding Icon}" Height="20" Width="20" VerticalAlignment="Center" Margin="0 0 5 0"/> <avalonia:MaterialIcon Kind="{CompiledBinding Icon}" Height="20" Width="20" VerticalAlignment="Center" Margin="0 0 5 0" />
<TextBlock Text="{CompiledBinding DisplayName}" VerticalAlignment="Center" /> <TextBlock Text="{CompiledBinding DisplayName}" VerticalAlignment="Center" />
</StackPanel> </StackPanel>
</DataTemplate> </DataTemplate>
@ -264,7 +279,7 @@
<StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center"> <StackPanel Grid.Row="0" Grid.Column="1" VerticalAlignment="Center">
<ComboBox Width="150" <ComboBox Width="150"
SelectedItem="{CompiledBinding CorePreferredGraphicsContext.Value}" SelectedItem="{CompiledBinding CorePreferredGraphicsContext.Value}"
Items="{CompiledBinding GraphicsContexts}"/> Items="{CompiledBinding GraphicsContexts}" />
</StackPanel> </StackPanel>
</Grid> </Grid>
<Separator Classes="card-separator" /> <Separator Classes="card-separator" />

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>();