diff --git a/src/Artemis.Core/Constants.cs b/src/Artemis.Core/Constants.cs
index e37f18ffb..f2abc9aa3 100644
--- a/src/Artemis.Core/Constants.cs
+++ b/src/Artemis.Core/Constants.cs
@@ -91,11 +91,6 @@ public static class Constants
///
public static readonly Plugin CorePlugin = new(CorePluginInfo, new DirectoryInfo(ApplicationFolder), null);
- ///
- /// Gets the startup arguments provided to the application
- ///
- public static ReadOnlyCollection StartupArguments { get; set; } = null!;
-
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")};
@@ -153,6 +148,11 @@ public static class Constants
typeof(decimal)
};
+ ///
+ /// Gets the startup arguments provided to the application
+ ///
+ public static ReadOnlyCollection StartupArguments { get; set; } = null!;
+
///
/// Gets the graphics context to be used for rendering by SkiaSharp. Can be set via
/// .
diff --git a/src/Artemis.Core/Events/Profiles/LayerPropertyKeyframeEventArgs.cs b/src/Artemis.Core/Events/Profiles/LayerPropertyKeyframeEventArgs.cs
index 962240239..5a46b7c7f 100644
--- a/src/Artemis.Core/Events/Profiles/LayerPropertyKeyframeEventArgs.cs
+++ b/src/Artemis.Core/Events/Profiles/LayerPropertyKeyframeEventArgs.cs
@@ -1,20 +1,19 @@
using System;
-namespace Artemis.Core
-{
- ///
- /// Provides data for layer property events.
- ///
- public class LayerPropertyKeyframeEventArgs : EventArgs
- {
- internal LayerPropertyKeyframeEventArgs(ILayerPropertyKeyframe keyframe)
- {
- Keyframe = keyframe;
- }
+namespace Artemis.Core;
- ///
- /// Gets the keyframe this event is related to
- ///
- public ILayerPropertyKeyframe Keyframe { get; }
+///
+/// Provides data for layer property events.
+///
+public class LayerPropertyKeyframeEventArgs : EventArgs
+{
+ internal LayerPropertyKeyframeEventArgs(ILayerPropertyKeyframe keyframe)
+ {
+ Keyframe = keyframe;
}
+
+ ///
+ /// Gets the keyframe this event is related to
+ ///
+ public ILayerPropertyKeyframe Keyframe { get; }
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Models/BreakableModel.cs b/src/Artemis.Core/Models/BreakableModel.cs
index 7276b6adb..1910cc2cc 100644
--- a/src/Artemis.Core/Models/BreakableModel.cs
+++ b/src/Artemis.Core/Models/BreakableModel.cs
@@ -69,11 +69,16 @@ public abstract class BreakableModel : CorePropertyChanged, IBreakableModel
///
public void ClearBrokenState(string state)
{
- if (state == null) throw new ArgumentNullException(nameof(state));
+ if (state == null)
+ throw new ArgumentNullException(nameof(state));
+
+ // If there was no broken state to begin with, done!
if (BrokenState == null)
return;
+ // Only clear similar broken states
+ if (BrokenState != state)
+ return;
- if (BrokenState != state) return;
BrokenState = null;
BrokenStateException = null;
OnBrokenStateChanged();
diff --git a/src/Artemis.Core/Services/Interfaces/ICoreService.cs b/src/Artemis.Core/Services/Interfaces/ICoreService.cs
index 8dd297038..66de54365 100644
--- a/src/Artemis.Core/Services/Interfaces/ICoreService.cs
+++ b/src/Artemis.Core/Services/Interfaces/ICoreService.cs
@@ -1,5 +1,4 @@
using System;
-using System.Collections.Generic;
namespace Artemis.Core.Services;
@@ -27,7 +26,7 @@ public interface ICoreService : IArtemisService, IDisposable
/// Gets or sets whether profiles are rendered each frame by calling their Render method
///
bool ProfileRenderingDisabled { get; set; }
-
+
///
/// Gets a boolean indicating whether Artemis is running in an elevated environment (admin permissions)
///
diff --git a/src/Artemis.Core/Services/NodeService.cs b/src/Artemis.Core/Services/NodeService.cs
index 2a9d7de6d..867fe8cb3 100644
--- a/src/Artemis.Core/Services/NodeService.cs
+++ b/src/Artemis.Core/Services/NodeService.cs
@@ -115,7 +115,7 @@ internal class NodeService : INodeService
}
}
- node.Initialize(script);
+ node.TryInitialize(script);
return node;
}
diff --git a/src/Artemis.Core/Services/PluginManagementService.cs b/src/Artemis.Core/Services/PluginManagementService.cs
index c5eba9608..dc5d1e3b1 100644
--- a/src/Artemis.Core/Services/PluginManagementService.cs
+++ b/src/Artemis.Core/Services/PluginManagementService.cs
@@ -233,7 +233,7 @@ internal class PluginManagementService : IPluginManagementService
}
catch (Exception e)
{
- _logger.Warning(new ArtemisPluginException("Failed to load plugin", e), "Plugin exception");
+ _logger.Warning(new ArtemisPluginException($"Failed to load plugin at {subDirectory}", e), "Plugin exception");
}
}
diff --git a/src/Artemis.Core/Services/ProcessMonitor/ProcessComparer.cs b/src/Artemis.Core/Services/ProcessMonitor/ProcessComparer.cs
new file mode 100644
index 000000000..14ac5e765
--- /dev/null
+++ b/src/Artemis.Core/Services/ProcessMonitor/ProcessComparer.cs
@@ -0,0 +1,20 @@
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace Artemis.Core.Services;
+
+internal class ProcessComparer : IEqualityComparer
+{
+ public bool Equals(Process? x, Process? y)
+ {
+ if (x == null && y == null) return true;
+ if (x == null || y == null) return false;
+ return x.Id == y.Id && x.ProcessName == y.ProcessName && x.SessionId == y.SessionId;
+ }
+
+ public int GetHashCode(Process? obj)
+ {
+ if (obj == null) return 0;
+ return obj.Id;
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs b/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs
index e5da142a7..fffcc100d 100644
--- a/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs
+++ b/src/Artemis.Core/Services/ProcessMonitor/ProcessMonitorService.cs
@@ -4,7 +4,6 @@ using System.Diagnostics;
using System.Linq;
using System.Timers;
using Artemis.Core.Modules;
-using Serilog;
namespace Artemis.Core.Services;
@@ -42,20 +41,4 @@ internal class ProcessMonitorService : IProcessMonitorService
{
return _lastScannedProcesses;
}
-}
-
-internal class ProcessComparer : IEqualityComparer
-{
- public bool Equals(Process? x, Process? y)
- {
- if (x == null && y == null) return true;
- if (x == null || y == null) return false;
- return x.Id == y.Id && x.ProcessName == y.ProcessName && x.SessionId == y.SessionId;
- }
-
- public int GetHashCode(Process? obj)
- {
- if (obj == null) return 0;
- return obj.Id;
- }
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Services/WebServer/WebServerService.cs b/src/Artemis.Core/Services/WebServer/WebServerService.cs
index f082ed6df..83d269fc4 100644
--- a/src/Artemis.Core/Services/WebServer/WebServerService.cs
+++ b/src/Artemis.Core/Services/WebServer/WebServerService.cs
@@ -38,6 +38,24 @@ internal class WebServerService : IWebServerService, IDisposable
StartWebServer();
}
+ public event EventHandler? WebServerStopped;
+ public event EventHandler? WebServerStarted;
+
+ 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);
+ }
+
private void WebServerEnabledSettingOnSettingChanged(object? sender, EventArgs e)
{
StartWebServer();
@@ -76,6 +94,7 @@ internal class WebServerService : IWebServerService, IDisposable
public WebServer? Server { get; private set; }
public PluginsModule PluginsModule { get; }
+ public event EventHandler? WebServerStarting;
#region Web server managament
@@ -129,7 +148,7 @@ internal class WebServerService : IWebServerService, IDisposable
if (!_webServerEnabledSetting.Value)
return;
-
+
if (Constants.StartupArguments.Contains("--disable-webserver"))
{
_logger.Warning("Artemis launched with --disable-webserver, not enabling the webserver");
@@ -302,27 +321,4 @@ internal class WebServerService : IWebServerService, IDisposable
}
#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
}
\ No newline at end of file
diff --git a/src/Artemis.Core/Stores/NodeTypeStore.cs b/src/Artemis.Core/Stores/NodeTypeStore.cs
index 401db6406..fb96f2794 100644
--- a/src/Artemis.Core/Stores/NodeTypeStore.cs
+++ b/src/Artemis.Core/Stores/NodeTypeStore.cs
@@ -62,9 +62,10 @@ internal class NodeTypeStore
public static Plugin? GetPlugin(INode node)
{
+ Type nodeType = node.GetType();
lock (Registrations)
{
- return Registrations.FirstOrDefault(r => r.Plugin.GetType().Assembly == node.GetType().Assembly)?.Plugin;
+ return Registrations.FirstOrDefault(r => r.NodeData.Type == nodeType)?.Plugin;
}
}
diff --git a/src/Artemis.Core/Utilities/Numeric.cs b/src/Artemis.Core/Utilities/Numeric.cs
index 36f04e14f..8fda4c66b 100644
--- a/src/Artemis.Core/Utilities/Numeric.cs
+++ b/src/Artemis.Core/Utilities/Numeric.cs
@@ -48,7 +48,7 @@ public readonly struct Numeric : IComparable, IConvertible
{
_value = value;
}
-
+
///
/// Creates a new instance of from a
///
@@ -160,10 +160,25 @@ public readonly struct Numeric : IComparable, IConvertible
return (byte) Math.Clamp(p._value, 0, 255);
}
- public static implicit operator Numeric(double d) => new(d);
- public static implicit operator Numeric(float f) => new(f);
- public static implicit operator Numeric(int i) => new(i);
- public static implicit operator Numeric(byte b) => new(b);
+ public static implicit operator Numeric(double d)
+ {
+ return new Numeric(d);
+ }
+
+ public static implicit operator Numeric(float f)
+ {
+ return new Numeric(f);
+ }
+
+ public static implicit operator Numeric(int i)
+ {
+ return new Numeric(i);
+ }
+
+ public static implicit operator Numeric(byte b)
+ {
+ return new Numeric(b);
+ }
public static implicit operator long(Numeric p)
{
diff --git a/src/Artemis.Core/VisualScripting/InputPin.cs b/src/Artemis.Core/VisualScripting/InputPin.cs
index 9db82c693..90933f31b 100644
--- a/src/Artemis.Core/VisualScripting/InputPin.cs
+++ b/src/Artemis.Core/VisualScripting/InputPin.cs
@@ -1,6 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
using Newtonsoft.Json;
namespace Artemis.Core;
@@ -96,7 +94,7 @@ public sealed class InputPin : Pin
{
if (type == _type)
return;
-
+
base.ChangeType(type, ref _type);
Value = type.GetDefault();
}
@@ -111,9 +109,13 @@ public sealed class InputPin : Pin
Value = Type.GetDefault()!;
}
else if (ConnectedTo.Count > 0)
+ {
Value = ConnectedTo[0].PinValue;
+ }
else
+ {
Value = null;
+ }
}
#endregion
diff --git a/src/Artemis.Core/VisualScripting/Interfaces/INode.cs b/src/Artemis.Core/VisualScripting/Interfaces/INode.cs
index b5e16a50b..022cddfaa 100644
--- a/src/Artemis.Core/VisualScripting/Interfaces/INode.cs
+++ b/src/Artemis.Core/VisualScripting/Interfaces/INode.cs
@@ -8,7 +8,7 @@ namespace Artemis.Core;
///
/// Represents a kind of node inside a
///
-public interface INode : INotifyPropertyChanged
+public interface INode : INotifyPropertyChanged, IBreakableModel
{
///
/// Gets or sets the ID of the node.
@@ -59,7 +59,7 @@ public interface INode : INotifyPropertyChanged
/// Called when the node resets
///
event EventHandler Resetting;
-
+
///
/// Occurs when a pin was added to the node
///
@@ -69,7 +69,7 @@ public interface INode : INotifyPropertyChanged
/// Occurs when a pin was removed from the node
///
event EventHandler> PinRemoved;
-
+
///
/// Occurs when a pin collection was added to the node
///
@@ -81,15 +81,15 @@ public interface INode : INotifyPropertyChanged
event EventHandler> PinCollectionRemoved;
///
- /// Called when the node was loaded from storage or newly created
+ /// Attempts to initialize the node.
///
/// The script the node is contained in
- void Initialize(INodeScript script);
+ void TryInitialize(INodeScript script);
///
- /// Evaluates the value of the output pins of this node
+ /// Attempts to evaluate the value of the output pins of this node
///
- void Evaluate();
+ void TryEvaluate();
///
/// Resets the node causing all pins to re-evaluate the next time is called
diff --git a/src/Artemis.Core/VisualScripting/Interfaces/IPin.cs b/src/Artemis.Core/VisualScripting/Interfaces/IPin.cs
index 67a0619c3..be3f1868e 100644
--- a/src/Artemis.Core/VisualScripting/Interfaces/IPin.cs
+++ b/src/Artemis.Core/VisualScripting/Interfaces/IPin.cs
@@ -85,7 +85,10 @@ public interface IPin
/// Determines whether this pin is compatible with the given type
///
/// The type to check for compatibility
- /// A boolean indicating whether or not enums should be exactly equal or just both be enums
+ ///
+ /// A boolean indicating whether or not enums should be exactly equal or just both be
+ /// enums
+ ///
/// if the type is compatible, otherwise .
public bool IsTypeCompatible(Type type, bool forgivingEnumMatching = true);
}
\ No newline at end of file
diff --git a/src/Artemis.Core/VisualScripting/Internal/DataBindingExitNode.cs b/src/Artemis.Core/VisualScripting/Internal/DataBindingExitNode.cs
index cd7818b41..6b4d367f5 100644
--- a/src/Artemis.Core/VisualScripting/Internal/DataBindingExitNode.cs
+++ b/src/Artemis.Core/VisualScripting/Internal/DataBindingExitNode.cs
@@ -26,6 +26,17 @@ internal class DataBindingExitNode : Node, IExitNode
property.SetValue(pendingValue);
}
+ public override void Evaluate()
+ {
+ foreach ((IDataBindingProperty? property, InputPin? inputPin) in _propertyPins)
+ {
+ if (inputPin.ConnectedTo.Any())
+ _propertyValues[property] = inputPin.Value!;
+ else
+ _propertyValues.Remove(property);
+ }
+ }
+
private void ClearInputPins()
{
while (Pins.Any())
@@ -59,15 +70,4 @@ internal class DataBindingExitNode : Node, IExitNode
}
public override bool IsExitNode => true;
-
- public override void Evaluate()
- {
- foreach ((IDataBindingProperty? property, InputPin? inputPin) in _propertyPins)
- {
- if (inputPin.ConnectedTo.Any())
- _propertyValues[property] = inputPin.Value!;
- else
- _propertyValues.Remove(property);
- }
- }
}
\ No newline at end of file
diff --git a/src/Artemis.Core/VisualScripting/Node.cs b/src/Artemis.Core/VisualScripting/Node.cs
index 5c1ccb03f..7e2161580 100644
--- a/src/Artemis.Core/VisualScripting/Node.cs
+++ b/src/Artemis.Core/VisualScripting/Node.cs
@@ -12,7 +12,7 @@ namespace Artemis.Core;
///
/// Represents a kind of node inside a
///
-public abstract class Node : CorePropertyChanged, INode
+public abstract class Node : BreakableModel, INode
{
///
public event EventHandler? Resetting;
@@ -95,6 +95,9 @@ public abstract class Node : CorePropertyChanged, INode
///
public IReadOnlyCollection PinCollections => new ReadOnlyCollection(_pinCollections);
+ ///
+ public override string BrokenDisplayName => Name;
+
#endregion
#region Construtors
@@ -335,12 +338,17 @@ public abstract class Node : CorePropertyChanged, INode
return isRemoved;
}
- ///
+ ///
+ /// Called when the node was loaded from storage or newly created
+ ///
+ /// The script the node is contained in
public virtual void Initialize(INodeScript script)
{
}
- ///
+ ///
+ /// Evaluates the value of the output pins of this node
+ ///
public abstract void Evaluate();
///
@@ -354,6 +362,18 @@ public abstract class Node : CorePropertyChanged, INode
Resetting?.Invoke(this, EventArgs.Empty);
}
+ ///
+ public void TryInitialize(INodeScript script)
+ {
+ TryOrBreak(() => Initialize(script), "Failed to initialize");
+ }
+
+ ///
+ public void TryEvaluate()
+ {
+ TryOrBreak(Evaluate, "Failed to evaluate");
+ }
+
///
/// Called whenever the node must show it's custom view model, if , no custom view model is used
///
diff --git a/src/Artemis.Core/VisualScripting/NodeScript.cs b/src/Artemis.Core/VisualScripting/NodeScript.cs
index 8abc29fbd..1c77626f8 100644
--- a/src/Artemis.Core/VisualScripting/NodeScript.cs
+++ b/src/Artemis.Core/VisualScripting/NodeScript.cs
@@ -14,13 +14,19 @@ namespace Artemis.Core;
///
public abstract class NodeScript : CorePropertyChanged, INodeScript
{
- private void NodeTypeStoreOnNodeTypeChanged(object? sender, NodeTypeStoreEvent e)
+ private void NodeTypeStoreOnNodeTypeAdded(object? sender, NodeTypeStoreEvent e)
{
- // Only respond to node changes applicable to the current script
if (Entity.Nodes.Any(n => e.TypeRegistration.MatchesEntity(n)))
Load();
}
+ private void NodeTypeStoreOnNodeTypeRemoved(object? sender, NodeTypeStoreEvent e)
+ {
+ List nodes = Nodes.Where(n => n.GetType() == e.TypeRegistration.NodeData.Type).ToList();
+ foreach (INode node in nodes)
+ RemoveNode(node);
+ }
+
///
public event EventHandler>? NodeAdded;
@@ -79,8 +85,8 @@ public abstract class NodeScript : CorePropertyChanged, INodeScript
Entity = new NodeScriptEntity();
ExitNode = null!;
- NodeTypeStore.NodeTypeAdded += NodeTypeStoreOnNodeTypeChanged;
- NodeTypeStore.NodeTypeRemoved += NodeTypeStoreOnNodeTypeChanged;
+ NodeTypeStore.NodeTypeAdded += NodeTypeStoreOnNodeTypeAdded;
+ NodeTypeStore.NodeTypeRemoved += NodeTypeStoreOnNodeTypeRemoved;
}
internal NodeScript(string name, string description, NodeScriptEntity entity, object? context = null)
@@ -91,8 +97,8 @@ public abstract class NodeScript : CorePropertyChanged, INodeScript
Context = context;
ExitNode = null!;
- NodeTypeStore.NodeTypeAdded += NodeTypeStoreOnNodeTypeChanged;
- NodeTypeStore.NodeTypeRemoved += NodeTypeStoreOnNodeTypeChanged;
+ NodeTypeStore.NodeTypeAdded += NodeTypeStoreOnNodeTypeAdded;
+ NodeTypeStore.NodeTypeRemoved += NodeTypeStoreOnNodeTypeRemoved;
}
#endregion
@@ -108,7 +114,7 @@ public abstract class NodeScript : CorePropertyChanged, INodeScript
node.Reset();
}
- ExitNode.Evaluate();
+ ExitNode.TryEvaluate();
}
///
@@ -136,8 +142,8 @@ public abstract class NodeScript : CorePropertyChanged, INodeScript
///
public void Dispose()
{
- NodeTypeStore.NodeTypeAdded -= NodeTypeStoreOnNodeTypeChanged;
- NodeTypeStore.NodeTypeRemoved -= NodeTypeStoreOnNodeTypeChanged;
+ NodeTypeStore.NodeTypeAdded -= NodeTypeStoreOnNodeTypeAdded;
+ NodeTypeStore.NodeTypeRemoved -= NodeTypeStoreOnNodeTypeRemoved;
lock (_nodes)
{
@@ -346,7 +352,7 @@ public abstract class NodeScript : CorePropertyChanged, INodeScript
sourcePinId++;
continue;
}
-
+
foreach (IPin targetPin in sourcePin.ConnectedTo)
{
int targetPinCollectionId = -1;
diff --git a/src/Artemis.Core/VisualScripting/OutputPin.cs b/src/Artemis.Core/VisualScripting/OutputPin.cs
index 2e135eb13..52bd0993a 100644
--- a/src/Artemis.Core/VisualScripting/OutputPin.cs
+++ b/src/Artemis.Core/VisualScripting/OutputPin.cs
@@ -1,6 +1,4 @@
using System;
-using System.Collections.Generic;
-using System.Linq;
using Newtonsoft.Json;
namespace Artemis.Core;
@@ -43,7 +41,7 @@ public sealed class OutputPin : Pin
get
{
if (!IsEvaluated)
- Node?.Evaluate();
+ Node?.TryEvaluate();
return _value;
}
@@ -115,7 +113,7 @@ public sealed class OutputPin : Pin
get
{
if (!IsEvaluated)
- Node?.Evaluate();
+ Node?.TryEvaluate();
return _value;
}
diff --git a/src/Artemis.Core/VisualScripting/Pin.cs b/src/Artemis.Core/VisualScripting/Pin.cs
index a562f7961..742e0e4b7 100644
--- a/src/Artemis.Core/VisualScripting/Pin.cs
+++ b/src/Artemis.Core/VisualScripting/Pin.cs
@@ -143,30 +143,20 @@ public abstract class Pin : CorePropertyChanged, IPin
/// The backing field of the current type of the pin.
protected void ChangeType(Type type, ref Type currentType)
{
- // Enums are a special case that disconnect and, if still compatible, reconnect
- if (type.IsEnum && currentType.IsEnum)
- {
- List connections = new(ConnectedTo);
- DisconnectAll();
+ if (currentType == type)
+ return;
- // Change the type
- SetAndNotify(ref currentType, type, nameof(Type));
- IsNumeric = type == typeof(Numeric);
+ bool changingEnums = type.IsEnum && currentType.IsEnum;
- foreach (IPin pin in connections.Where(p => p.IsTypeCompatible(type)))
- ConnectTo(pin);
- }
- // Disconnect pins incompatible with the new type
- else
- {
- List toDisconnect = ConnectedTo.Where(p => !p.IsTypeCompatible(type, false)).ToList();
- foreach (IPin pin in toDisconnect)
- DisconnectFrom(pin);
+ List connections = new(ConnectedTo);
+ DisconnectAll();
- // Change the type
- SetAndNotify(ref currentType, type, nameof(Type));
- IsNumeric = type == typeof(Numeric);
- }
+ // Change the type
+ SetAndNotify(ref currentType, type, nameof(Type));
+ IsNumeric = type == typeof(Numeric);
+
+ foreach (IPin pin in connections.Where(p => p.IsTypeCompatible(type, changingEnums)))
+ ConnectTo(pin);
}
#endregion
diff --git a/src/Artemis.UI.Linux/Providers/Input/LinuxInputProvider.cs b/src/Artemis.UI.Linux/Providers/Input/LinuxInputProvider.cs
index 26c5c36ed..e735a8ed9 100644
--- a/src/Artemis.UI.Linux/Providers/Input/LinuxInputProvider.cs
+++ b/src/Artemis.UI.Linux/Providers/Input/LinuxInputProvider.cs
@@ -33,14 +33,12 @@ public class LinuxInputProvider : InputProvider
protected override void Dispose(bool disposing)
{
if (disposing)
- {
for (int i = _readers.Count - 1; i >= 0; i--)
{
_readers[i].InputEvent -= OnInputEvent;
_readers[i].Dispose();
_readers.RemoveAt(i);
}
- }
base.Dispose(disposing);
}
@@ -51,7 +49,7 @@ public class LinuxInputProvider : InputProvider
{
if (sender is not LinuxInputDeviceReader reader)
return;
-
+
switch (reader.InputDevice.DeviceType)
{
case LinuxDeviceType.Keyboard:
@@ -69,7 +67,7 @@ public class LinuxInputProvider : InputProvider
{
if (args.Type != LinuxInputEventType.KEY)
return;
-
+
KeyboardKey key = InputUtilities.KeyFromKeyCode((LinuxKeyboardKeyCodes) args.Code);
bool isDown = args.Value != 0;
diff --git a/src/Artemis.UI.Shared/Behaviors/LostFocusNumericUpDownBindingBehavior.cs b/src/Artemis.UI.Shared/Behaviors/LostFocusNumericUpDownBindingBehavior.cs
index 3c73456a7..23e2bdbdb 100644
--- a/src/Artemis.UI.Shared/Behaviors/LostFocusNumericUpDownBindingBehavior.cs
+++ b/src/Artemis.UI.Shared/Behaviors/LostFocusNumericUpDownBindingBehavior.cs
@@ -4,7 +4,6 @@ using Avalonia.Controls;
using Avalonia.Data;
using Avalonia.Interactivity;
using Avalonia.Xaml.Interactivity;
-using FluentAvalonia.UI.Controls;
namespace Artemis.UI.Shared.Behaviors;
diff --git a/src/Artemis.UI.Shared/Services/MainWindow/IMainWindowService.cs b/src/Artemis.UI.Shared/Services/MainWindow/IMainWindowService.cs
index c19b06c78..bf7716f0b 100644
--- a/src/Artemis.UI.Shared/Services/MainWindow/IMainWindowService.cs
+++ b/src/Artemis.UI.Shared/Services/MainWindow/IMainWindowService.cs
@@ -19,12 +19,12 @@ public interface IMainWindowService : IArtemisSharedUIService
void ConfigureMainWindowProvider(IMainWindowProvider mainWindowProvider);
///
- /// Opens the main window if it is not already open
+ /// Opens the main window if it is not already open, must be called on the UI thread
///
void OpenMainWindow();
///
- /// Closes the main window if it is not already closed
+ /// Closes the main window if it is not already closed, must be called on the UI thread
///
void CloseMainWindow();
@@ -37,7 +37,7 @@ public interface IMainWindowService : IArtemisSharedUIService
/// Occurs when the main window has been closed
///
public event EventHandler? MainWindowClosed;
-
+
///
/// Occurs when the main window has been focused
///
diff --git a/src/Artemis.UI.Shared/Services/MainWindow/MainWindowService.cs b/src/Artemis.UI.Shared/Services/MainWindow/MainWindowService.cs
index 407bec98b..fbdda52e1 100644
--- a/src/Artemis.UI.Shared/Services/MainWindow/MainWindowService.cs
+++ b/src/Artemis.UI.Shared/Services/MainWindow/MainWindowService.cs
@@ -15,7 +15,7 @@ internal class MainWindowService : IMainWindowService
{
MainWindowClosed?.Invoke(this, EventArgs.Empty);
}
-
+
protected virtual void OnMainWindowFocused()
{
MainWindowFocused?.Invoke(this, EventArgs.Empty);
@@ -53,7 +53,7 @@ internal class MainWindowService : IMainWindowService
{
SyncWithManager();
}
-
+
private void HandleMainWindowFocused(object? sender, EventArgs e)
{
OnMainWindowFocused();
@@ -83,7 +83,7 @@ internal class MainWindowService : IMainWindowService
_mainWindowManager.MainWindowClosed += HandleMainWindowClosed;
_mainWindowManager.MainWindowFocused += HandleMainWindowFocused;
_mainWindowManager.MainWindowUnfocused += HandleMainWindowUnfocused;
-
+
// Sync up with the new manager's state
SyncWithManager();
}
diff --git a/src/Artemis.UI.Shared/Services/NodeEditor/Commands/ConnectPins.cs b/src/Artemis.UI.Shared/Services/NodeEditor/Commands/ConnectPins.cs
index 0b65a56e1..1898745b1 100644
--- a/src/Artemis.UI.Shared/Services/NodeEditor/Commands/ConnectPins.cs
+++ b/src/Artemis.UI.Shared/Services/NodeEditor/Commands/ConnectPins.cs
@@ -1,5 +1,4 @@
-using System.Collections.Generic;
-using System.Linq;
+using System.Linq;
using Artemis.Core;
namespace Artemis.UI.Shared.Services.NodeEditor.Commands;
@@ -9,9 +8,9 @@ namespace Artemis.UI.Shared.Services.NodeEditor.Commands;
///
public class ConnectPins : INodeEditorCommand
{
- private readonly IPin _output;
private readonly IPin _input;
private readonly IPin? _originalConnection;
+ private readonly IPin _output;
///
/// Creates a new instance of the class.
diff --git a/src/Artemis.UI.Shared/Services/NodeEditor/NodeConnectionStore.cs b/src/Artemis.UI.Shared/Services/NodeEditor/NodeConnectionStore.cs
index 596e66304..8182aec2b 100644
--- a/src/Artemis.UI.Shared/Services/NodeEditor/NodeConnectionStore.cs
+++ b/src/Artemis.UI.Shared/Services/NodeEditor/NodeConnectionStore.cs
@@ -31,7 +31,7 @@ public class NodeConnectionStore
public void Store()
{
_pinConnections.Clear();
-
+
// Iterate to save
foreach (IPin nodePin in Node.Pins.ToList())
_pinConnections.Add(nodePin, new List(nodePin.ConnectedTo));
diff --git a/src/Artemis.UI.Windows/App.axaml.cs b/src/Artemis.UI.Windows/App.axaml.cs
index f82d58f29..c41c00aa1 100644
--- a/src/Artemis.UI.Windows/App.axaml.cs
+++ b/src/Artemis.UI.Windows/App.axaml.cs
@@ -24,11 +24,6 @@ public class App : Application
private StandardKernel? _kernel;
private bool _shutDown;
- // ReSharper disable NotAccessedField.Local
- private ApplicationStateManager? _applicationStateManager;
- private Mutex? _artemisMutex;
- // ReSharper restore NotAccessedField.Local
-
public override void Initialize()
{
// If Artemis is already running, bring it to foreground and stop this process
@@ -110,4 +105,10 @@ public class App : Application
}
}
}
+
+ // ReSharper disable NotAccessedField.Local
+ private ApplicationStateManager? _applicationStateManager;
+
+ private Mutex? _artemisMutex;
+ // ReSharper restore NotAccessedField.Local
}
\ No newline at end of file
diff --git a/src/Artemis.UI.Windows/Providers/Input/WindowsInputProvider.cs b/src/Artemis.UI.Windows/Providers/Input/WindowsInputProvider.cs
index 605e23892..d834c3002 100644
--- a/src/Artemis.UI.Windows/Providers/Input/WindowsInputProvider.cs
+++ b/src/Artemis.UI.Windows/Providers/Input/WindowsInputProvider.cs
@@ -17,10 +17,10 @@ public class WindowsInputProvider : InputProvider
private readonly IInputService _inputService;
private readonly ILogger _logger;
+ private readonly SpongeWindow _sponge;
private readonly Timer _taskManagerTimer;
private DateTime _lastMouseUpdate;
private int _lastProcessId;
- private readonly SpongeWindow _sponge;
public WindowsInputProvider(ILogger logger, IInputService inputService)
{
diff --git a/src/Artemis.UI.Windows/Providers/UpdateProvider.cs b/src/Artemis.UI.Windows/Providers/UpdateProvider.cs
index 788c02231..40ffbc776 100644
--- a/src/Artemis.UI.Windows/Providers/UpdateProvider.cs
+++ b/src/Artemis.UI.Windows/Providers/UpdateProvider.cs
@@ -24,8 +24,8 @@ namespace Artemis.UI.Windows.Providers;
public class UpdateProvider : IUpdateProvider, IDisposable
{
- private const string ApiUrl = "https://dev.azure.com/artemis-rgb/Artemis/_apis/";
- private const string InstallerUrl = "https://builds.artemis-rgb.com/binaries/Artemis.Installer.exe";
+ private const string API_URL = "https://dev.azure.com/artemis-rgb/Artemis/_apis/";
+ private const string INSTALLER_URL = "https://builds.artemis-rgb.com/binaries/Artemis.Installer.exe";
private readonly ILogger _logger;
private readonly IMainWindowService _mainWindowService;
@@ -42,7 +42,7 @@ public class UpdateProvider : IUpdateProvider, IDisposable
public async Task GetBuildInfo(int buildDefinition, string? buildNumber = null)
{
- Url request = ApiUrl.AppendPathSegments("build", "builds")
+ Url request = API_URL.AppendPathSegments("build", "builds")
.SetQueryParam("definitions", buildDefinition)
.SetQueryParam("resultFilter", "succeeded")
.SetQueryParam("$top", 1)
@@ -143,9 +143,9 @@ public class UpdateProvider : IUpdateProvider, IDisposable
string installerDirectory = Path.Combine(Constants.DataFolder, "installer");
string installerPath = Path.Combine(installerDirectory, "Artemis.Installer.exe");
- _logger.Information("UpdateInstaller: Downloading installer from {DownloadUrl}", InstallerUrl);
+ _logger.Information("UpdateInstaller: Downloading installer from {DownloadUrl}", INSTALLER_URL);
using HttpClient client = new();
- HttpResponseMessage httpResponseMessage = await client.GetAsync(InstallerUrl);
+ HttpResponseMessage httpResponseMessage = await client.GetAsync(INSTALLER_URL);
if (!httpResponseMessage.IsSuccessStatusCode)
throw new ArtemisUIException($"Failed to download installer, status code {httpResponseMessage.StatusCode}");
diff --git a/src/Artemis.UI/ArtemisBootstrapper.cs b/src/Artemis.UI/ArtemisBootstrapper.cs
index 7bade4f67..901388bf8 100644
--- a/src/Artemis.UI/ArtemisBootstrapper.cs
+++ b/src/Artemis.UI/ArtemisBootstrapper.cs
@@ -1,7 +1,6 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
-using System.Linq;
using System.Reactive;
using Artemis.Core;
using Artemis.Core.Ninject;
diff --git a/src/Artemis.UI/Controllers/RemoteController.cs b/src/Artemis.UI/Controllers/RemoteController.cs
index 15db2f0ef..56b88ef6a 100644
--- a/src/Artemis.UI/Controllers/RemoteController.cs
+++ b/src/Artemis.UI/Controllers/RemoteController.cs
@@ -2,6 +2,7 @@ using System;
using Artemis.Core;
using Artemis.Core.Services;
using Artemis.UI.Shared.Services.MainWindow;
+using Avalonia.Threading;
using EmbedIO;
using EmbedIO.Routing;
using EmbedIO.WebApi;
@@ -22,7 +23,7 @@ public class RemoteController : WebApiController
[Route(HttpVerbs.Post, "/remote/bring-to-foreground")]
public void PostBringToForeground()
{
- _mainWindowService.OpenMainWindow();
+ Dispatcher.UIThread.Post(() => _mainWindowService.OpenMainWindow());
}
[Route(HttpVerbs.Post, "/remote/restart")]
diff --git a/src/Artemis.UI/MainWindow.axaml.cs b/src/Artemis.UI/MainWindow.axaml.cs
index a22f46831..14732e730 100644
--- a/src/Artemis.UI/MainWindow.axaml.cs
+++ b/src/Artemis.UI/MainWindow.axaml.cs
@@ -44,7 +44,7 @@ public class MainWindow : ReactiveCoreWindow
SetTitleBar(this.Get("DragHandle"));
}
}
-
+
private void OnActivated(object? sender, EventArgs e)
{
ViewModel?.Focused();
diff --git a/src/Artemis.UI/Screens/Device/DevicePropertiesViewModel.cs b/src/Artemis.UI/Screens/Device/DevicePropertiesViewModel.cs
index 98ea28983..d0200cb70 100644
--- a/src/Artemis.UI/Screens/Device/DevicePropertiesViewModel.cs
+++ b/src/Artemis.UI/Screens/Device/DevicePropertiesViewModel.cs
@@ -37,6 +37,16 @@ public class DevicePropertiesViewModel : DialogViewModelBase
-
-
diff --git a/src/Artemis.UI/Screens/VisualScripting/NodeViewModel.cs b/src/Artemis.UI/Screens/VisualScripting/NodeViewModel.cs
index bb3a1670d..e8777e411 100644
--- a/src/Artemis.UI/Screens/VisualScripting/NodeViewModel.cs
+++ b/src/Artemis.UI/Screens/VisualScripting/NodeViewModel.cs
@@ -8,6 +8,7 @@ using Artemis.Core.Events;
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Screens.VisualScripting.Pins;
using Artemis.UI.Shared;
+using Artemis.UI.Shared.Services;
using Artemis.UI.Shared.Services.NodeEditor;
using Artemis.UI.Shared.Services.NodeEditor.Commands;
using Avalonia;
@@ -21,9 +22,9 @@ namespace Artemis.UI.Screens.VisualScripting;
public class NodeViewModel : ActivatableViewModelBase
{
private readonly INodeEditorService _nodeEditorService;
+ private readonly IWindowService _windowService;
private ICustomNodeViewModel? _customNodeViewModel;
- private ReactiveCommand? _deleteNode;
private double _dragOffsetX;
private double _dragOffsetY;
private ObservableAsPropertyHelper? _hasInputPins;
@@ -34,14 +35,13 @@ public class NodeViewModel : ActivatableViewModelBase
private double _startX;
private double _startY;
- public NodeViewModel(NodeScriptViewModel nodeScriptViewModel, INode node, INodeVmFactory nodeVmFactory, INodeEditorService nodeEditorService)
+ public NodeViewModel(NodeScriptViewModel nodeScriptViewModel, INode node, INodeVmFactory nodeVmFactory, INodeEditorService nodeEditorService, IWindowService windowService)
{
_nodeEditorService = nodeEditorService;
+ _windowService = windowService;
NodeScriptViewModel = nodeScriptViewModel;
Node = node;
- DeleteNode = ReactiveCommand.Create(ExecuteDeleteNode, this.WhenAnyValue(vm => vm.IsStaticNode).Select(v => !v));
-
SourceList nodePins = new();
SourceList nodePinCollections = new();
@@ -62,6 +62,9 @@ public class NodeViewModel : ActivatableViewModelBase
PinViewModels = pins;
+ DeleteNode = ReactiveCommand.Create(ExecuteDeleteNode, this.WhenAnyValue(vm => vm.IsStaticNode).Select(v => !v));
+ ShowBrokenState = ReactiveCommand.Create(ExecuteShowBrokenState);
+
this.WhenActivated(d =>
{
_isStaticNode = Node.WhenAnyValue(n => n.IsDefaultNode, n => n.IsExitNode)
@@ -90,7 +93,7 @@ public class NodeViewModel : ActivatableViewModelBase
})
.DisposeWith(d);
Observable.FromEventPattern>(x => Node.PinRemoved += x, x => Node.PinRemoved -= x)
- .Subscribe(p => nodePins!.Remove(nodePins.Items.FirstOrDefault(vm => vm.Pin == p.EventArgs.Value)))
+ .Subscribe(p => nodePins.RemoveMany(nodePins.Items.Where(vm => vm.Pin == p.EventArgs.Value)))
.DisposeWith(d);
nodePins.Edit(l =>
{
@@ -115,7 +118,7 @@ public class NodeViewModel : ActivatableViewModelBase
})
.DisposeWith(d);
Observable.FromEventPattern>(x => Node.PinCollectionRemoved += x, x => Node.PinCollectionRemoved -= x)
- .Subscribe(p => nodePinCollections!.Remove(nodePinCollections.Items.FirstOrDefault(vm => vm.PinCollection == p.EventArgs.Value)))
+ .Subscribe(p => nodePinCollections.RemoveMany(nodePinCollections.Items.Where(vm => vm.PinCollection == p.EventArgs.Value)))
.DisposeWith(d);
nodePinCollections.Edit(l =>
{
@@ -152,18 +155,15 @@ public class NodeViewModel : ActivatableViewModelBase
set => RaiseAndSetIfChanged(ref _customNodeViewModel, value);
}
- public ReactiveCommand? DeleteNode
- {
- get => _deleteNode;
- set => RaiseAndSetIfChanged(ref _deleteNode, value);
- }
-
public bool IsSelected
{
get => _isSelected;
set => RaiseAndSetIfChanged(ref _isSelected, value);
}
+ public ReactiveCommand ShowBrokenState { get; }
+ public ReactiveCommand DeleteNode { get; }
+
public void StartDrag(Point mouseStartPosition)
{
if (!IsSelected)
@@ -195,4 +195,10 @@ public class NodeViewModel : ActivatableViewModelBase
{
_nodeEditorService.ExecuteCommand(NodeScriptViewModel.NodeScript, new DeleteNode(NodeScriptViewModel.NodeScript, Node));
}
+
+ private void ExecuteShowBrokenState()
+ {
+ if (Node.BrokenState != null && Node.BrokenStateException != null)
+ _windowService.ShowExceptionDialog(Node.BrokenState, Node.BrokenStateException);
+ }
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/VisualScripting/Pins/PinCollectionViewModel.cs b/src/Artemis.UI/Screens/VisualScripting/Pins/PinCollectionViewModel.cs
index 782e80131..d6e160dc4 100644
--- a/src/Artemis.UI/Screens/VisualScripting/Pins/PinCollectionViewModel.cs
+++ b/src/Artemis.UI/Screens/VisualScripting/Pins/PinCollectionViewModel.cs
@@ -30,7 +30,7 @@ public abstract class PinCollectionViewModel : ActivatableViewModelBase
.Subscribe(e => PinViewModels.Add(CreatePinViewModel(e.EventArgs.Value)))
.DisposeWith(d);
Observable.FromEventPattern>(x => PinCollection.PinRemoved += x, x => PinCollection.PinRemoved -= x)
- .Subscribe(e => PinViewModels.RemoveMany(PinViewModels.Where(p => p.Pin == e.EventArgs.Value).ToList()))
+ .Subscribe(e => PinViewModels.RemoveMany(PinViewModels.Where(p => p.Pin == e.EventArgs.Value)))
.DisposeWith(d);
});
diff --git a/src/Artemis.UI/Screens/VisualScripting/Pins/PinViewModel.cs b/src/Artemis.UI/Screens/VisualScripting/Pins/PinViewModel.cs
index 8eae87607..37542daca 100644
--- a/src/Artemis.UI/Screens/VisualScripting/Pins/PinViewModel.cs
+++ b/src/Artemis.UI/Screens/VisualScripting/Pins/PinViewModel.cs
@@ -1,4 +1,5 @@
using System;
+using System.Linq;
using System.Reactive;
using System.Reactive.Linq;
using Artemis.Core;
@@ -38,7 +39,7 @@ public abstract class PinViewModel : ActivatableViewModelBase
.Subscribe(e => connectedPins.Add(e.EventArgs.Value))
.DisposeWith(d);
Observable.FromEventPattern>(x => Pin.PinDisconnected += x, x => Pin.PinDisconnected -= x)
- .Subscribe(e => connectedPins.Remove(e.EventArgs.Value))
+ .Subscribe(e => connectedPins.RemoveMany(connectedPins.Items.Where(p => p == e.EventArgs.Value)))
.DisposeWith(d);
Pin.WhenAnyValue(p => p.Type).Subscribe(_ => UpdatePinColor()).DisposeWith(d);
});
diff --git a/src/Artemis.VisualScripting/Nodes/Text/StringRegexMatchNode.cs b/src/Artemis.VisualScripting/Nodes/Text/StringRegexMatchNode.cs
index c3c1d1a8b..810080877 100644
--- a/src/Artemis.VisualScripting/Nodes/Text/StringRegexMatchNode.cs
+++ b/src/Artemis.VisualScripting/Nodes/Text/StringRegexMatchNode.cs
@@ -8,7 +8,7 @@ public class StringRegexMatchNode : Node
{
private string? _lastPattern;
private Regex? _regex;
- private bool _broken;
+ private Exception? _exception;
public StringRegexMatchNode() : base("Regex Match", "Checks provided regex pattern matches the input.")
{
@@ -25,20 +25,27 @@ public class StringRegexMatchNode : Node
{
if (Input.Value == null || Pattern.Value == null)
return;
- if (_broken && _lastPattern == Pattern.Value)
- return;
+ // If the regex was invalid output false and rethrow the exception
+ if (_lastPattern == Pattern.Value && _exception != null)
+ {
+ Result.Value = false;
+ throw _exception;
+ }
+
+ // If there is no regex yet or the regex changed, recompile
if (_regex == null || _lastPattern != Pattern.Value)
{
try
{
_regex = new Regex(Pattern.Value, RegexOptions.Compiled);
- _broken = false;
+ _exception = null;
}
- catch (Exception)
+ catch (Exception e)
{
- _broken = true;
- return;
+ // If there is an exception, save it to keep rethrowing until the regex is fixed
+ _exception = e;
+ throw;
}
finally
{