diff --git a/src/Artemis.Core/Constants.cs b/src/Artemis.Core/Constants.cs index 7d455e13e..69208acb3 100644 --- a/src/Artemis.Core/Constants.cs +++ b/src/Artemis.Core/Constants.cs @@ -38,7 +38,7 @@ namespace Artemis.Core /// /// The full path to the Artemis data folder /// - public static readonly string DataFolder = Path.Combine(BaseFolder, "Artemis.Avalonia"); + public static readonly string DataFolder = Path.Combine(BaseFolder, "Artemis"); /// /// The full path to the Artemis logs folder diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs index 6966ff44c..b0bab4093 100644 --- a/src/Artemis.Core/Models/Profile/Layer.cs +++ b/src/Artemis.Core/Models/Profile/Layer.cs @@ -382,7 +382,7 @@ namespace Artemis.Core if (ShouldBeEnabled) Enable(); - else if (Timeline.IsFinished && !_renderCopies.Any()) + else if (Suspended || (Timeline.IsFinished && !_renderCopies.Any())) Disable(); if (Timeline.Delta == TimeSpan.Zero) diff --git a/src/Artemis.Core/Utilities/Numeric.cs b/src/Artemis.Core/Utilities/Numeric.cs index d96516148..09b64603f 100644 --- a/src/Artemis.Core/Utilities/Numeric.cs +++ b/src/Artemis.Core/Utilities/Numeric.cs @@ -60,6 +60,7 @@ namespace Artemis.Core int value => value, double value => (float) value, byte value => value, + Numeric value => value, _ => ParseFloatOrDefault(pathValue?.ToString()) }; } diff --git a/src/Artemis.Core/VisualScripting/InputPin.cs b/src/Artemis.Core/VisualScripting/InputPin.cs index 2b218fb44..1efb780d0 100644 --- a/src/Artemis.Core/VisualScripting/InputPin.cs +++ b/src/Artemis.Core/VisualScripting/InputPin.cs @@ -17,6 +17,7 @@ namespace Artemis.Core : base(node, name) { Value = default; + IsNumeric = typeof(T) == typeof(Numeric); } #endregion @@ -80,6 +81,7 @@ namespace Artemis.Core { _type = type; _value = type.GetDefault(); + IsNumeric = type == typeof(Numeric); } #endregion @@ -103,6 +105,7 @@ namespace Artemis.Core // Change the type SetAndNotify(ref _type, type, nameof(Type)); Value = type.GetDefault(); + IsNumeric = type == typeof(Numeric); } private void Evaluate() @@ -169,7 +172,7 @@ namespace Artemis.Core OnPropertyChanged(nameof(PinValue)); } } - + #endregion } } \ No newline at end of file diff --git a/src/Artemis.Core/VisualScripting/Interfaces/IPin.cs b/src/Artemis.Core/VisualScripting/Interfaces/IPin.cs index 197f40365..a9389fc40 100644 --- a/src/Artemis.Core/VisualScripting/Interfaces/IPin.cs +++ b/src/Artemis.Core/VisualScripting/Interfaces/IPin.cs @@ -29,6 +29,11 @@ namespace Artemis.Core /// Type Type { get; } + /// + /// Gets a boolean indicating whether the type of this pin is numeric. + /// + bool IsNumeric { get; } + /// /// Gets the value the pin holds /// diff --git a/src/Artemis.Core/VisualScripting/Internal/EventConditionEventStartNode.cs b/src/Artemis.Core/VisualScripting/Internal/EventConditionEventStartNode.cs index c169e0555..4aa4eca1a 100644 --- a/src/Artemis.Core/VisualScripting/Internal/EventConditionEventStartNode.cs +++ b/src/Artemis.Core/VisualScripting/Internal/EventConditionEventStartNode.cs @@ -47,7 +47,10 @@ internal class EventConditionEventStartNode : DefaultNode, IEventConditionNode foreach ((PropertyInfo propertyInfo, OutputPin outputPin) in _propertyPins) { if (outputPin.ConnectedTo.Any()) - outputPin.Value = propertyInfo.GetValue(_dataModelEvent.LastEventArgumentsUntyped) ?? outputPin.Type.GetDefault()!; + { + object value = propertyInfo.GetValue(_dataModelEvent.LastEventArgumentsUntyped) ?? outputPin.Type.GetDefault()!; + outputPin.Value = outputPin.IsNumeric ? new Numeric(value) : value; + } } } @@ -61,6 +64,9 @@ internal class EventConditionEventStartNode : DefaultNode, IEventConditionNode // Grab the first pin from the bucket that isn't on the node yet OutputPin? pin = _pinBucket.FirstOrDefault(p => !Pins.Contains(p)); + if (Numeric.IsTypeCompatible(valueType)) + valueType = typeof(Numeric); + // If there is none, create a new one and add it to the bucket if (pin == null) { diff --git a/src/Artemis.Core/VisualScripting/Internal/EventConditionValueChangedStartNode.cs b/src/Artemis.Core/VisualScripting/Internal/EventConditionValueChangedStartNode.cs index 5bbf1d77b..abf571979 100644 --- a/src/Artemis.Core/VisualScripting/Internal/EventConditionValueChangedStartNode.cs +++ b/src/Artemis.Core/VisualScripting/Internal/EventConditionValueChangedStartNode.cs @@ -20,10 +20,11 @@ internal class EventConditionValueChangedStartNode : DefaultNode, IEventConditio public void UpdateOutputPins(DataModelPath dataModelPath) { - Type? type = dataModelPath?.GetPropertyType(); - if (Numeric.IsTypeCompatible(type)) + Type? type = dataModelPath.GetPropertyType(); + if (type == null) + type = typeof(object); + else if (Numeric.IsTypeCompatible(type)) type = typeof(Numeric); - type ??= typeof(object); if (NewValue.Type != type) NewValue.ChangeType(type); @@ -33,8 +34,8 @@ internal class EventConditionValueChangedStartNode : DefaultNode, IEventConditio public void UpdateValues(object? newValue, object? oldValue) { - _newValue = newValue; - _oldValue = oldValue; + _newValue = NewValue.IsNumeric ? new Numeric(newValue) : newValue; + _oldValue = OldValue.IsNumeric ? new Numeric(oldValue) : oldValue; } /// diff --git a/src/Artemis.Core/VisualScripting/OutputPin.cs b/src/Artemis.Core/VisualScripting/OutputPin.cs index a2b1ce1f0..0027c867f 100644 --- a/src/Artemis.Core/VisualScripting/OutputPin.cs +++ b/src/Artemis.Core/VisualScripting/OutputPin.cs @@ -17,6 +17,7 @@ namespace Artemis.Core : base(node, name) { _value = default; + IsNumeric = typeof(T) == typeof(Numeric); } #endregion @@ -70,6 +71,7 @@ namespace Artemis.Core { _type = type; _value = type.GetDefault(); + IsNumeric = type == typeof(Numeric); } #endregion @@ -90,6 +92,7 @@ namespace Artemis.Core // Change the type SetAndNotify(ref _type, type, nameof(Type)); Value = type.GetDefault(); + IsNumeric = type == typeof(Numeric); } #endregion diff --git a/src/Artemis.Core/VisualScripting/Pin.cs b/src/Artemis.Core/VisualScripting/Pin.cs index 46916fae5..b9626f87e 100644 --- a/src/Artemis.Core/VisualScripting/Pin.cs +++ b/src/Artemis.Core/VisualScripting/Pin.cs @@ -50,10 +50,19 @@ namespace Artemis.Core get => _isEvaluated; set => SetAndNotify(ref _isEvaluated, value); } + + private bool _isNumeric; + + /// + public bool IsNumeric + { + get => _isNumeric; + protected set => SetAndNotify(ref _isNumeric, value); + } private readonly List _connectedTo = new(); private string _name; - + /// public IReadOnlyList ConnectedTo => new ReadOnlyCollection(_connectedTo); diff --git a/src/Artemis.UI/Screens/Debugger/Tabs/DataModel/DataModelDebugViewModel.cs b/src/Artemis.UI/Screens/Debugger/Tabs/DataModel/DataModelDebugViewModel.cs index b64aaedc9..86793643e 100644 --- a/src/Artemis.UI/Screens/Debugger/Tabs/DataModel/DataModelDebugViewModel.cs +++ b/src/Artemis.UI/Screens/Debugger/Tabs/DataModel/DataModelDebugViewModel.cs @@ -32,7 +32,7 @@ public class DataModelDebugViewModel : ActivatableViewModelBase, IRoutableViewMo { _dataModelUIService = dataModelUIService; _pluginManagementService = pluginManagementService; - _updateTimer = new DispatcherTimer(TimeSpan.FromMilliseconds(25), DispatcherPriority.Normal, (_, _) => Update()); + _updateTimer = new DispatcherTimer(TimeSpan.FromMilliseconds(25), DispatcherPriority.DataBind, (_, _) => Update()); HostScreen = hostScreen; Modules = new ObservableCollection(); diff --git a/src/Artemis.UI/Screens/Plugins/PluginSettingsViewModel.cs b/src/Artemis.UI/Screens/Plugins/PluginSettingsViewModel.cs index 5c1baf29d..6a7c6c9fb 100644 --- a/src/Artemis.UI/Screens/Plugins/PluginSettingsViewModel.cs +++ b/src/Artemis.UI/Screens/Plugins/PluginSettingsViewModel.cs @@ -1,4 +1,5 @@ using System.Collections.ObjectModel; +using System.Linq; using System.Reactive; using System.Threading.Tasks; using Artemis.Core; @@ -13,52 +14,36 @@ namespace Artemis.UI.Screens.Plugins; public class PluginSettingsViewModel : ActivatableViewModelBase { private Plugin _plugin; - - private readonly ISettingsVmFactory _settingsVmFactory; + private readonly IPluginManagementService _pluginManagementService; private readonly INotificationService _notificationService; - - private PluginViewModel _pluginViewModel; public PluginSettingsViewModel(Plugin plugin, ISettingsVmFactory settingsVmFactory, IPluginManagementService pluginManagementService, INotificationService notificationService) { _plugin = plugin; - _settingsVmFactory = settingsVmFactory; _pluginManagementService = pluginManagementService; _notificationService = notificationService; Reload = ReactiveCommand.CreateFromTask(ExecuteReload); - PluginViewModel = settingsVmFactory.PluginViewModel(_plugin, Reload); - PluginFeatures = new ObservableCollection(); - foreach (PluginFeatureInfo pluginFeatureInfo in _plugin.Features) - PluginFeatures.Add(settingsVmFactory.PluginFeatureViewModel(pluginFeatureInfo, false)); + PluginFeatures = new ObservableCollection(_plugin.Features.Select(f => settingsVmFactory.PluginFeatureViewModel(f, false))); } public ReactiveCommand Reload { get; } - public PluginViewModel PluginViewModel - { - get => _pluginViewModel; - private set => RaiseAndSetIfChanged(ref _pluginViewModel, value); - } + public PluginViewModel PluginViewModel { get; } public ObservableCollection PluginFeatures { get; } private async Task ExecuteReload() { + // Unloading the plugin will remove this viewmodel, this method is it's final act 😭 bool wasEnabled = _plugin.IsEnabled; await Task.Run(() => _pluginManagementService.UnloadPlugin(_plugin)); - PluginFeatures.Clear(); _plugin = _pluginManagementService.LoadPlugin(_plugin.Directory); - - PluginViewModel = _settingsVmFactory.PluginViewModel(_plugin, Reload); - foreach (PluginFeatureInfo pluginFeatureInfo in _plugin.Features) - PluginFeatures.Add(_settingsVmFactory.PluginFeatureViewModel(pluginFeatureInfo, false)); - if (wasEnabled) - await PluginViewModel.UpdateEnabled(true); + await Task.Run(() => _pluginManagementService.EnablePlugin(_plugin, true, true)); _notificationService.CreateNotification().WithTitle("Reloaded plugin.").Show(); } diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/DisplayConditionScriptViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/DisplayConditionScriptViewModel.cs index 3568cfff7..260270e6b 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/DisplayConditionScriptViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/DisplayCondition/DisplayConditionScriptViewModel.cs @@ -44,7 +44,7 @@ public class DisplayConditionScriptViewModel : ActivatableViewModelBase .DisposeWith(d); }); - _conditionViewModel = this.WhenAnyValue(vm => vm.SelectedConditionTypeViewModel).Select(_ => CreateConditionViewModel()).ToProperty(this, vm => vm.ConditionViewModel); + _conditionViewModel = this.WhenAnyValue(vm => vm.SelectedConditionTypeViewModel, vm => vm.ProfileElement).Select(_ => CreateConditionViewModel()).ToProperty(this, vm => vm.ConditionViewModel); } public RenderProfileElement? ProfileElement => _profileElement?.Value; diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemView.axaml index 021b19b77..7889634a4 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/FolderTreeItemView.axaml @@ -40,6 +40,7 @@ Classes="icon-button icon-button-small" ToolTip.Tip="Toggle suspended state" IsChecked="{CompiledBinding Folder.Suspended}" + Focusable="False" VerticalAlignment="Center" Margin="4 0"> diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/LayerTreeItemView.axaml b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/LayerTreeItemView.axaml index 81907f35d..240a164d6 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/LayerTreeItemView.axaml +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/LayerTreeItemView.axaml @@ -31,6 +31,7 @@ Classes="icon-button icon-button-small" ToolTip.Tip="Toggle suspended state" IsChecked="{CompiledBinding Layer.Suspended}" + Focusable="False" VerticalAlignment="Center" Margin="4 0"> diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/TreeItemViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/TreeItemViewModel.cs index 8773076e5..a9ad9f829 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/TreeItemViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/ProfileTree/TreeItemViewModel.cs @@ -31,6 +31,7 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase private ProfileElement? _profileElement; private string? _renameValue; private bool _renaming; + private TimeSpan _time; protected TreeItemViewModel(TreeItemViewModel? parent, ProfileElement? profileElement, @@ -56,6 +57,7 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase this.WhenActivated(d => { + ProfileEditorService.Time.Subscribe(t => _time = t).DisposeWith(d); ProfileEditorService.ProfileElement.Subscribe(element => _currentProfileElement = element).DisposeWith(d); SubscribeToProfileElement(d); CreateTreeItems(); @@ -173,6 +175,7 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase Observable.FromEventPattern(x => ProfileElement.ChildRemoved += x, x => ProfileElement.ChildRemoved -= x) .Subscribe(c => RemoveTreeItemsIfFound(c.Sender, c.EventArgs.ProfileElement)) .DisposeWith(d); + ProfileElement.WhenAnyValue(e => e.Suspended).Subscribe(_ => ProfileEditorService.ChangeTime(_time)).DisposeWith(d); } protected void RemoveTreeItemsIfFound(object? sender, ProfileElement profileElement) diff --git a/src/Artemis.VisualScripting/Nodes/DataModel/DataModelNode.cs b/src/Artemis.VisualScripting/Nodes/DataModel/DataModelNode.cs index 6a9a39c82..411f7c1f1 100644 --- a/src/Artemis.VisualScripting/Nodes/DataModel/DataModelNode.cs +++ b/src/Artemis.VisualScripting/Nodes/DataModel/DataModelNode.cs @@ -42,16 +42,17 @@ public class DataModelNode : Node