From 563389cab6392fd1c4a3e0fc2d9cfec15a1661bb Mon Sep 17 00:00:00 2001 From: Robert Date: Sun, 21 Aug 2022 13:34:10 +0200 Subject: [PATCH] Profile editor - Fixed play on focus loss functionality --- .../Controls/DeviceVisualizer.cs | 2 +- .../MainWindow/IMainWindowProvider.cs | 15 +++++++++ .../Services/MainWindow/IMainWindowService.cs | 10 ++++++ .../Services/MainWindow/MainWindowService.cs | 29 ++++++++++++++++- src/Artemis.UI/MainWindow.axaml.cs | 12 +++++++ .../VisualEditor/VisualEditorViewModel.cs | 2 +- .../ProfileEditor/ProfileEditorViewModel.cs | 27 +++++++++++++++- src/Artemis.UI/Screens/Root/RootViewModel.cs | 31 +++++++++++++++++++ 8 files changed, 124 insertions(+), 4 deletions(-) diff --git a/src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs b/src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs index 6e031cb97..c3fd4fc6e 100644 --- a/src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs +++ b/src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs @@ -321,7 +321,7 @@ public class DeviceVisualizer : Control { // ignored } - }, DispatcherPriority.Background); + }); } /// diff --git a/src/Artemis.UI.Shared/Services/MainWindow/IMainWindowProvider.cs b/src/Artemis.UI.Shared/Services/MainWindow/IMainWindowProvider.cs index 07650f4c6..036b8e55c 100644 --- a/src/Artemis.UI.Shared/Services/MainWindow/IMainWindowProvider.cs +++ b/src/Artemis.UI.Shared/Services/MainWindow/IMainWindowProvider.cs @@ -14,6 +14,11 @@ public interface IMainWindowProvider /// bool IsMainWindowOpen { get; } + /// + /// Gets a boolean indicating whether the main window is currently focused + /// + bool IsMainWindowFocused { get; } + /// /// Opens the main window /// @@ -33,4 +38,14 @@ public interface IMainWindowProvider /// Occurs when the main window has been closed /// public event EventHandler? MainWindowClosed; + + /// + /// Occurs when the main window has been focused + /// + public event EventHandler? MainWindowFocused; + + /// + /// Occurs when the main window has been unfocused + /// + public event EventHandler? MainWindowUnfocused; } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Services/MainWindow/IMainWindowService.cs b/src/Artemis.UI.Shared/Services/MainWindow/IMainWindowService.cs index 3018fba73..c19b06c78 100644 --- a/src/Artemis.UI.Shared/Services/MainWindow/IMainWindowService.cs +++ b/src/Artemis.UI.Shared/Services/MainWindow/IMainWindowService.cs @@ -37,4 +37,14 @@ public interface IMainWindowService : IArtemisSharedUIService /// Occurs when the main window has been closed /// public event EventHandler? MainWindowClosed; + + /// + /// Occurs when the main window has been focused + /// + public event EventHandler? MainWindowFocused; + + /// + /// Occurs when the main window has been unfocused + /// + public event EventHandler? MainWindowUnfocused; } \ No newline at end of file diff --git a/src/Artemis.UI.Shared/Services/MainWindow/MainWindowService.cs b/src/Artemis.UI.Shared/Services/MainWindow/MainWindowService.cs index 9fc6b742a..407bec98b 100644 --- a/src/Artemis.UI.Shared/Services/MainWindow/MainWindowService.cs +++ b/src/Artemis.UI.Shared/Services/MainWindow/MainWindowService.cs @@ -15,6 +15,16 @@ internal class MainWindowService : IMainWindowService { MainWindowClosed?.Invoke(this, EventArgs.Empty); } + + protected virtual void OnMainWindowFocused() + { + MainWindowFocused?.Invoke(this, EventArgs.Empty); + } + + protected virtual void OnMainWindowUnfocused() + { + MainWindowUnfocused?.Invoke(this, EventArgs.Empty); + } private void SyncWithManager() { @@ -43,6 +53,16 @@ internal class MainWindowService : IMainWindowService { SyncWithManager(); } + + private void HandleMainWindowFocused(object? sender, EventArgs e) + { + OnMainWindowFocused(); + } + + private void HandleMainWindowUnfocused(object? sender, EventArgs e) + { + OnMainWindowUnfocused(); + } public bool IsMainWindowOpen { get; private set; } @@ -54,12 +74,16 @@ internal class MainWindowService : IMainWindowService { _mainWindowManager.MainWindowOpened -= HandleMainWindowOpened; _mainWindowManager.MainWindowClosed -= HandleMainWindowClosed; + _mainWindowManager.MainWindowFocused -= HandleMainWindowFocused; + _mainWindowManager.MainWindowUnfocused -= HandleMainWindowUnfocused; } _mainWindowManager = mainWindowProvider; _mainWindowManager.MainWindowOpened += HandleMainWindowOpened; _mainWindowManager.MainWindowClosed += HandleMainWindowClosed; - + _mainWindowManager.MainWindowFocused += HandleMainWindowFocused; + _mainWindowManager.MainWindowUnfocused += HandleMainWindowUnfocused; + // Sync up with the new manager's state SyncWithManager(); } @@ -76,4 +100,7 @@ internal class MainWindowService : IMainWindowService public event EventHandler? MainWindowOpened; public event EventHandler? MainWindowClosed; + + public event EventHandler? MainWindowFocused; + public event EventHandler? MainWindowUnfocused; } \ No newline at end of file diff --git a/src/Artemis.UI/MainWindow.axaml.cs b/src/Artemis.UI/MainWindow.axaml.cs index 2bbede9b3..df0371090 100644 --- a/src/Artemis.UI/MainWindow.axaml.cs +++ b/src/Artemis.UI/MainWindow.axaml.cs @@ -16,6 +16,8 @@ public class MainWindow : ReactiveCoreWindow public MainWindow() { Opened += OnOpened; + Activated += OnActivated; + Deactivated += OnDeactivated; InitializeComponent(); _rootPanel = this.Get("RootPanel"); _sidebarContentControl = this.Get("SidebarContentControl"); @@ -42,6 +44,16 @@ public class MainWindow : ReactiveCoreWindow SetTitleBar(this.Get("DragHandle")); } } + + private void OnActivated(object? sender, EventArgs e) + { + ViewModel.Focused(); + } + + private void OnDeactivated(object? sender, EventArgs e) + { + ViewModel.Unfocused(); + } private void InitializeComponent() { diff --git a/src/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/VisualEditorViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/VisualEditorViewModel.cs index 592914c52..4e767743d 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/VisualEditorViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/Panels/VisualEditor/VisualEditorViewModel.cs @@ -34,7 +34,7 @@ public class VisualEditorViewModel : ActivatableViewModelBase .Bind(out ReadOnlyObservableCollection visualizers) .Subscribe(); - Devices = new ObservableCollection(rgbService.EnabledDevices); + Devices = new ObservableCollection(rgbService.EnabledDevices.OrderBy(d => d.ZIndex)); Visualizers = visualizers; this.WhenActivated(d => diff --git a/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs index 2cf4f602b..24a29ad59 100644 --- a/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs +++ b/src/Artemis.UI/Screens/ProfileEditor/ProfileEditorViewModel.cs @@ -11,6 +11,7 @@ using Artemis.UI.Screens.ProfileEditor.ProfileTree; using Artemis.UI.Screens.ProfileEditor.Properties; using Artemis.UI.Screens.ProfileEditor.StatusBar; using Artemis.UI.Screens.ProfileEditor.VisualEditor; +using Artemis.UI.Shared.Services.MainWindow; using Artemis.UI.Shared.Services.ProfileEditor; using Avalonia.Threading; using DynamicData; @@ -23,6 +24,7 @@ public class ProfileEditorViewModel : MainScreenViewModel { private readonly IProfileEditorService _profileEditorService; private readonly ISettingsService _settingsService; + private readonly IMainWindowService _mainWindowService; private readonly SourceList _tools; private DisplayConditionScriptViewModel? _displayConditionScriptViewModel; private ObservableAsPropertyHelper? _history; @@ -43,11 +45,13 @@ public class ProfileEditorViewModel : MainScreenViewModel PropertiesViewModel propertiesViewModel, DisplayConditionScriptViewModel displayConditionScriptViewModel, StatusBarViewModel statusBarViewModel, - IEnumerable toolViewModels) + IEnumerable toolViewModels, + IMainWindowService mainWindowService) : base(hostScreen, "profile-editor") { _profileEditorService = profileEditorService; _settingsService = settingsService; + _mainWindowService = mainWindowService; _tools = new SourceList(); _tools.AddRange(toolViewModels); @@ -65,7 +69,16 @@ public class ProfileEditorViewModel : MainScreenViewModel _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); + + mainWindowService.MainWindowFocused += MainWindowServiceOnMainWindowFocused; + mainWindowService.MainWindowUnfocused += MainWindowServiceOnMainWindowUnfocused; + Disposable.Create(() => + { + mainWindowService.MainWindowFocused -= MainWindowServiceOnMainWindowFocused; + mainWindowService.MainWindowUnfocused -= MainWindowServiceOnMainWindowUnfocused; + }).DisposeWith(d); + // 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); @@ -152,4 +165,16 @@ public class ProfileEditorViewModel : MainScreenViewModel toolViewModel.IsSelected = false; }); } + + private void MainWindowServiceOnMainWindowFocused(object? sender, EventArgs e) + { + if (_settingsService.GetSetting("ProfileEditor.AutoSuspend", true).Value) + _profileEditorService.ChangeSuspendedEditing(false); + } + + private void MainWindowServiceOnMainWindowUnfocused(object? sender, EventArgs e) + { + if (_settingsService.GetSetting("ProfileEditor.AutoSuspend", true).Value) + _profileEditorService.ChangeSuspendedEditing(true); + } } \ No newline at end of file diff --git a/src/Artemis.UI/Screens/Root/RootViewModel.cs b/src/Artemis.UI/Screens/Root/RootViewModel.cs index e37fbba58..0845b50e7 100644 --- a/src/Artemis.UI/Screens/Root/RootViewModel.cs +++ b/src/Artemis.UI/Screens/Root/RootViewModel.cs @@ -157,6 +157,9 @@ public class RootViewModel : ActivatableViewModelBase, IScreen, IMainWindowProvi /// public bool IsMainWindowOpen => _lifeTime.MainWindow != null; + /// + public bool IsMainWindowFocused { get; private set; } + /// public void OpenMainWindow() { @@ -181,12 +184,30 @@ public class RootViewModel : ActivatableViewModelBase, IScreen, IMainWindowProvi { Dispatcher.UIThread.Post(() => { _lifeTime.MainWindow?.Close(); }); } + + public void Focused() + { + IsMainWindowFocused = true; + OnMainWindowFocused(); + } + + public void Unfocused() + { + IsMainWindowFocused = false; + OnMainWindowUnfocused(); + } /// public event EventHandler? MainWindowOpened; /// public event EventHandler? MainWindowClosed; + + /// + public event EventHandler? MainWindowFocused; + + /// + public event EventHandler? MainWindowUnfocused; protected virtual void OnMainWindowOpened() { @@ -197,6 +218,16 @@ public class RootViewModel : ActivatableViewModelBase, IScreen, IMainWindowProvi { MainWindowClosed?.Invoke(this, EventArgs.Empty); } + + protected virtual void OnMainWindowFocused() + { + MainWindowFocused?.Invoke(this, EventArgs.Empty); + } + + protected virtual void OnMainWindowUnfocused() + { + MainWindowUnfocused?.Invoke(this, EventArgs.Empty); + } #endregion }