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

Editor - Fixed a bunch of memory leaks

This commit is contained in:
Robert 2022-08-18 20:13:15 +02:00
parent 84b394fc51
commit 9da71f7b97
6 changed files with 60 additions and 93 deletions

View File

@ -60,12 +60,7 @@ public interface IProfileEditorService : IArtemisSharedUIService
/// Gets an observable of the suspended keybindings state.
/// </summary>
IObservable<ProfileEditorFocusMode> FocusMode { get; }
/// <summary>
/// Gets an observable read only collection of all available editor tools.
/// </summary>
ReadOnlyObservableCollection<IToolViewModel> Tools { get; }
/// <summary>
/// Gets an observable read only collection of selected keyframes.
/// </summary>
@ -209,16 +204,4 @@ public interface IProfileEditorService : IArtemisSharedUIService
/// Pauses profile preview playback.
/// </summary>
void Pause();
/// <summary>
/// Adds a profile editor tool by it's view model.
/// </summary>
/// <param name="toolViewModel">The view model of the tool to add.</param>
void AddTool(IToolViewModel toolViewModel);
/// <summary>
/// Removes a profile editor tool by it's view model.
/// </summary>
/// <param name="toolViewModel">The view model of the tool to remove.</param>
void RemoveTool(IToolViewModel toolViewModel);
}

View File

@ -33,7 +33,6 @@ internal class ProfileEditorService : IProfileEditorService
private readonly BehaviorSubject<bool> _suspendedKeybindingsSubject = new(false);
private readonly BehaviorSubject<ProfileEditorFocusMode> _focusModeSubject = new(ProfileEditorFocusMode.None);
private readonly BehaviorSubject<TimeSpan> _timeSubject = new(TimeSpan.Zero);
private readonly SourceList<IToolViewModel> _tools;
private readonly SourceList<ILayerPropertyKeyframe> _selectedKeyframes;
private readonly IWindowService _windowService;
private ProfileEditorCommandScope? _profileEditorHistoryScope;
@ -53,10 +52,7 @@ internal class ProfileEditorService : IProfileEditorService
_layerBrushService = layerBrushService;
_windowService = windowService;
_tools = new SourceList<IToolViewModel>();
_selectedKeyframes = new SourceList<ILayerPropertyKeyframe>();
_tools.Connect().AutoRefreshOnObservable(t => t.WhenAnyValue(vm => vm.IsSelected)).Subscribe(OnToolSelected);
_tools.Connect().Bind(out ReadOnlyObservableCollection<IToolViewModel> tools).Subscribe();
_selectedKeyframes.Connect().Bind(out ReadOnlyObservableCollection<ILayerPropertyKeyframe> selectedKeyframes).Subscribe();
ProfileConfiguration = _profileConfigurationSubject.AsObservable();
@ -69,8 +65,6 @@ internal class ProfileEditorService : IProfileEditorService
SuspendedKeybindings = _suspendedKeybindingsSubject.AsObservable();
PixelsPerSecond = _pixelsPerSecondSubject.AsObservable();
FocusMode = _focusModeSubject.AsObservable();
Tools = tools;
SelectedKeyframes = selectedKeyframes;
// Observe executing, undoing and redoing commands and run the auto-save after 1 second
@ -100,7 +94,6 @@ internal class ProfileEditorService : IProfileEditorService
public IObservable<bool> Playing { get; }
public IObservable<int> PixelsPerSecond { get; }
public IObservable<ProfileEditorFocusMode> FocusMode { get; }
public ReadOnlyObservableCollection<IToolViewModel> Tools { get; }
public ReadOnlyObservableCollection<ILayerPropertyKeyframe> SelectedKeyframes { get; }
public void ChangeCurrentProfileConfiguration(ProfileConfiguration? profileConfiguration)
@ -384,19 +377,7 @@ internal class ProfileEditorService : IProfileEditorService
if (_playingSubject.Value)
_playingSubject.OnNext(false);
}
/// <inheritdoc />
public void AddTool(IToolViewModel toolViewModel)
{
_tools.Add(toolViewModel);
}
/// <inheritdoc />
public void RemoveTool(IToolViewModel toolViewModel)
{
_tools.Remove(toolViewModel);
}
#region Commands
public void ExecuteCommand(IProfileEditorCommand command)
@ -451,22 +432,7 @@ internal class ProfileEditorService : IProfileEditorService
}
#endregion
private void OnToolSelected(IChangeSet<IToolViewModel> changeSet)
{
IToolViewModel? changed = changeSet.FirstOrDefault()?.Item.Current;
if (changed == null)
return;
// Disable all others if the changed one is selected and exclusive
if (changed.IsSelected && changed.IsExclusive)
_tools.Edit(list =>
{
foreach (IToolViewModel toolViewModel in list.Where(t => t.IsExclusive && t != changed))
toolViewModel.IsSelected = false;
});
}
private ProfileEditorHistory? GetHistory(ProfileConfiguration? profileConfiguration)
{
if (profileConfiguration == null)

View File

@ -62,7 +62,8 @@ public abstract class TreeItemViewModel : ActivatableViewModelBase
_isFocused = ProfileEditorService.FocusMode
.CombineLatest(ProfileEditorService.ProfileElement)
.Select(tuple => GetIsFocused(tuple.First, tuple.Second))
.ToProperty(this, vm => vm.IsFocused);
.ToProperty(this, vm => vm.IsFocused)
.DisposeWith(d);
ProfileEditorService.Time.Subscribe(t => _time = t).DisposeWith(d);
ProfileEditorService.ProfileElement.Subscribe(element => _currentProfileElement = element).DisposeWith(d);

View File

@ -43,15 +43,6 @@ public class VisualEditorViewModel : ActivatableViewModelBase
_suspendedEditing = profileEditorService.SuspendedEditing.ToProperty(this, vm => vm.SuspendedEditing).DisposeWith(d);
profileEditorService.ProfileConfiguration.Subscribe(CreateVisualizers).DisposeWith(d);
profileEditorService.Tools
.ToObservableChangeSet()
.AutoRefreshOnObservable(t => t.WhenAnyValue(vm => vm.IsSelected))
.Filter(t => t.IsSelected)
.Bind(out ReadOnlyObservableCollection<IToolViewModel> tools)
.Subscribe()
.DisposeWith(d);
Tools = tools;
this.WhenAnyValue(vm => vm.ProfileConfiguration)
.Select(p => p?.Profile)
.Select(p => p != null
@ -74,15 +65,15 @@ public class VisualEditorViewModel : ActivatableViewModelBase
public ProfileConfiguration? ProfileConfiguration => _profileConfiguration?.Value;
public bool SuspendedEditing => _suspendedEditing?.Value ?? false;
public ObservableCollection<ArtemisDevice> Devices { get; }
public ReadOnlyObservableCollection<IVisualizerViewModel> Visualizers { get; }
public ReadOnlyObservableCollection<IToolViewModel>? Tools
{
get => _tools;
set => RaiseAndSetIfChanged(ref _tools, value);
}
public ReadOnlyObservableCollection<IVisualizerViewModel> Visualizers { get; }
public ObservableCollection<ArtemisDevice> Devices { get; }
private void RemoveElement(EventPattern<ProfileElementEventArgs> eventPattern)
{
List<IVisualizerViewModel> visualizers = Visualizers.Where(v => v.ProfileElement == eventPattern.EventArgs.ProfileElement).ToList();
@ -113,7 +104,17 @@ public class VisualEditorViewModel : ActivatableViewModelBase
visualizerViewModels.Add(_vmFactory.LayerShapeVisualizerViewModel(layer));
visualizerViewModels.Add(_vmFactory.LayerVisualizerViewModel(layer));
}
public void SetTools(SourceList<IToolViewModel> tools)
{
tools.Connect()
.AutoRefreshOnObservable(t => t.WhenAnyValue(vm => vm.IsSelected))
.Filter(t => t.IsSelected)
.Bind(out ReadOnlyObservableCollection<IToolViewModel> selectedTools)
.Subscribe();
Tools = selectedTools;
}
public void RequestAutoFit()
{
AutoFitRequested?.Invoke(this, EventArgs.Empty);

View File

@ -1,5 +1,7 @@
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reactive;
using System.Reactive.Disposables;
using Artemis.Core;
@ -21,10 +23,10 @@ public class ProfileEditorViewModel : MainScreenViewModel
{
private readonly IProfileEditorService _profileEditorService;
private readonly ISettingsService _settingsService;
private readonly SourceList<IToolViewModel> _tools;
private ObservableAsPropertyHelper<ProfileEditorHistory?>? _history;
private ObservableAsPropertyHelper<ProfileConfiguration?>? _profileConfiguration;
private ObservableAsPropertyHelper<bool>? _suspendedEditing;
private ReadOnlyObservableCollection<IToolViewModel>? _tools;
private StatusBarViewModel _statusBarViewModel;
private DisplayConditionScriptViewModel _displayConditionScriptViewModel;
private PropertiesViewModel _propertiesViewModel;
@ -40,26 +42,30 @@ public class ProfileEditorViewModel : MainScreenViewModel
ProfileEditorTitleBarViewModel profileEditorTitleBarViewModel,
PropertiesViewModel propertiesViewModel,
DisplayConditionScriptViewModel displayConditionScriptViewModel,
StatusBarViewModel statusBarViewModel)
StatusBarViewModel statusBarViewModel,
IEnumerable<IToolViewModel> toolViewModels)
: base(hostScreen, "profile-editor")
{
_profileEditorService = profileEditorService;
_settingsService = settingsService;
_tools = new SourceList<IToolViewModel>();
_tools.AddRange(toolViewModels);
_tools.Connect().AutoRefreshOnObservable(t => t.WhenAnyValue(vm => vm.IsSelected)).Subscribe(OnToolSelected);
_tools.Connect()
.Filter(t => t.ShowInToolbar)
.Sort(SortExpressionComparer<IToolViewModel>.Ascending(vm => vm.Order))
.Bind(out ReadOnlyObservableCollection<IToolViewModel> tools)
.Subscribe();
Tools = tools;
visualEditorViewModel.SetTools(_tools);
this.WhenActivated(d =>
{
_profileConfiguration = profileEditorService.ProfileConfiguration.ToProperty(this, vm => vm.ProfileConfiguration).DisposeWith(d);
_history = profileEditorService.History.ToProperty(this, vm => vm.History).DisposeWith(d);
_suspendedEditing = profileEditorService.SuspendedEditing.ToProperty(this, vm => vm.SuspendedEditing).DisposeWith(d);
profileEditorService.Tools
.ToObservableChangeSet()
.Filter(t => t.ShowInToolbar)
.Sort(SortExpressionComparer<IToolViewModel>.Ascending(vm => vm.Order))
.Bind(out ReadOnlyObservableCollection<IToolViewModel> tools)
.Subscribe()
.DisposeWith(d);
Tools = tools;
// Slow and steady wins the race (and doesn't lock up the entire UI)
Dispatcher.UIThread.Post(() => StatusBarViewModel = statusBarViewModel, DispatcherPriority.Loaded);
Dispatcher.UIThread.Post(() => VisualEditorViewModel = visualEditorViewModel, DispatcherPriority.Loaded);
@ -103,12 +109,7 @@ public class ProfileEditorViewModel : MainScreenViewModel
set => RaiseAndSetIfChanged(ref _statusBarViewModel, value);
}
public ReadOnlyObservableCollection<IToolViewModel>? Tools
{
get => _tools;
set => RaiseAndSetIfChanged(ref _tools, value);
}
public ReadOnlyObservableCollection<IToolViewModel> Tools { get; }
public ProfileConfiguration? ProfileConfiguration => _profileConfiguration?.Value;
public ProfileEditorHistory? History => _history?.Value;
public bool SuspendedEditing => _suspendedEditing?.Value ?? false;
@ -134,4 +135,21 @@ public class ProfileEditorViewModel : MainScreenViewModel
setting.Value = !setting.Value;
setting.Save();
}
private void OnToolSelected(IChangeSet<IToolViewModel> changeSet)
{
IToolViewModel? changed = changeSet.FirstOrDefault()?.Item.Current;
if (changed == null)
return;
if (!changed.IsSelected || !changed.IsExclusive)
return;
// Disable all others if the changed one is selected and exclusive
_tools.Edit(list =>
{
foreach (IToolViewModel toolViewModel in list.Where(t => t.IsExclusive && t != changed))
toolViewModel.IsSelected = false;
});
}
}

View File

@ -27,14 +27,14 @@ public class RegistrationService : IRegistrationService
private readonly IDataModelUIService _dataModelUIService;
private bool _registeredBuiltInPropertyEditors;
public RegistrationService(IKernel kernel,
IInputService inputService,
public RegistrationService(IKernel kernel,
IInputService inputService,
IPropertyInputService propertyInputService,
IProfileEditorService profileEditorService,
INodeService nodeService,
INodeService nodeService,
IDataModelUIService dataModelUIService,
IDeviceLayoutService deviceLayoutService, // here to make sure it is instantiated
IEnumerable<IToolViewModel> toolViewModels)
IDeviceLayoutService deviceLayoutService // here to make sure it is instantiated
)
{
_kernel = kernel;
_inputService = inputService;
@ -42,8 +42,6 @@ public class RegistrationService : IRegistrationService
_nodeService = nodeService;
_dataModelUIService = dataModelUIService;
foreach (IToolViewModel toolViewModel in toolViewModels)
profileEditorService.AddTool(toolViewModel);
CreateCursorResources();
}
@ -90,7 +88,7 @@ public class RegistrationService : IRegistrationService
public void RegisterControllers()
{
}
public void RegisterBuiltInNodeTypes()
{
_nodeService.RegisterTypeColor(Constants.CorePlugin, typeof(bool), new SKColor(0xFFCD3232));