using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Linq; using System.Reactive; using System.Threading.Tasks; using Artemis.Core; using Artemis.Core.Services; using Artemis.UI.Extensions; using Artemis.UI.Ninject.Factories; using Avalonia; using ReactiveUI; namespace Artemis.UI.Screens.SurfaceEditor; public class SurfaceEditorViewModel : MainScreenViewModel { private readonly IRgbService _rgbService; private readonly ISettingsService _settingsService; private List? _initialSelection; private bool _saving; public SurfaceEditorViewModel(IScreen hostScreen, IRgbService rgbService, ISurfaceVmFactory surfaceVmFactory, ISettingsService settingsService) : base(hostScreen, "surface-editor") { _rgbService = rgbService; _settingsService = settingsService; DisplayName = "Surface Editor"; SurfaceDeviceViewModels = new ObservableCollection(rgbService.EnabledDevices.OrderBy(d => d.ZIndex).Select(d => surfaceVmFactory.SurfaceDeviceViewModel(d, this))); ListDeviceViewModels = new ObservableCollection(rgbService.EnabledDevices.OrderBy(d => d.ZIndex).Select(d => surfaceVmFactory.ListDeviceViewModel(d, this))); BringToFront = ReactiveCommand.Create(ExecuteBringToFront); BringForward = ReactiveCommand.Create(ExecuteBringForward); SendToBack = ReactiveCommand.Create(ExecuteSendToBack); SendBackward = ReactiveCommand.Create(ExecuteSendBackward); } public ObservableCollection SurfaceDeviceViewModels { get; } public ObservableCollection ListDeviceViewModels { get; } public ReactiveCommand BringToFront { get; } public ReactiveCommand BringForward { get; } public ReactiveCommand SendToBack { get; } public ReactiveCommand SendBackward { get; } public double MaxTextureSize => 4096 / _settingsService.GetSetting("Core.RenderScale", 0.25).Value; public void UpdateSelection(List devices, bool expand, bool invert) { _initialSelection ??= SurfaceDeviceViewModels.Where(d => d.IsSelected).ToList(); if (expand) { foreach (SurfaceDeviceViewModel surfaceDeviceViewModel in devices) surfaceDeviceViewModel.IsSelected = true; } else if (invert) { foreach (SurfaceDeviceViewModel surfaceDeviceViewModel in devices) surfaceDeviceViewModel.IsSelected = !_initialSelection.Contains(surfaceDeviceViewModel); } else { foreach (SurfaceDeviceViewModel surfaceDeviceViewModel in devices) surfaceDeviceViewModel.IsSelected = true; foreach (SurfaceDeviceViewModel surfaceDeviceViewModel in SurfaceDeviceViewModels.Except(devices)) surfaceDeviceViewModel.IsSelected = false; } } public void FinishSelection() { _initialSelection = null; if (_saving) return; Task.Run(() => { try { _saving = true; _rgbService.SaveDevices(); } finally { _saving = false; } }); } public void ClearSelection() { foreach (SurfaceDeviceViewModel surfaceDeviceViewModel in SurfaceDeviceViewModels) surfaceDeviceViewModel.IsSelected = false; } public void StartMouseDrag(Point mousePosition) { foreach (SurfaceDeviceViewModel surfaceDeviceViewModel in SurfaceDeviceViewModels) surfaceDeviceViewModel.StartMouseDrag(mousePosition); } public void UpdateMouseDrag(Point mousePosition, bool round, bool ignoreOverlap) { foreach (SurfaceDeviceViewModel surfaceDeviceViewModel in SurfaceDeviceViewModels) surfaceDeviceViewModel.UpdateMouseDrag(mousePosition, round, ignoreOverlap); } private void ApplySurfaceSelection() { foreach (ListDeviceViewModel viewModel in ListDeviceViewModels) viewModel.IsSelected = SurfaceDeviceViewModels.Any(s => s.Device == viewModel.Device && s.IsSelected); } #region Context menu commands private void ExecuteBringToFront(ArtemisDevice device) { SurfaceDeviceViewModel surfaceDeviceViewModel = SurfaceDeviceViewModels.First(d => d.Device == device); SurfaceDeviceViewModels.Move(SurfaceDeviceViewModels.IndexOf(surfaceDeviceViewModel), SurfaceDeviceViewModels.Count - 1); for (int i = 0; i < SurfaceDeviceViewModels.Count; i++) { SurfaceDeviceViewModel deviceViewModel = SurfaceDeviceViewModels[i]; deviceViewModel.Device.ZIndex = i + 1; } ListDeviceViewModels.Sort(l => l.Device.ZIndex * -1); _rgbService.SaveDevices(); } private void ExecuteBringForward(ArtemisDevice device) { SurfaceDeviceViewModel surfaceDeviceViewModel = SurfaceDeviceViewModels.First(d => d.Device == device); int currentIndex = SurfaceDeviceViewModels.IndexOf(surfaceDeviceViewModel); int newIndex = Math.Min(currentIndex + 1, SurfaceDeviceViewModels.Count - 1); SurfaceDeviceViewModels.Move(currentIndex, newIndex); for (int i = 0; i < SurfaceDeviceViewModels.Count; i++) { SurfaceDeviceViewModel deviceViewModel = SurfaceDeviceViewModels[i]; deviceViewModel.Device.ZIndex = i + 1; } ListDeviceViewModels.Sort(l => l.Device.ZIndex * -1); _rgbService.SaveDevices(); } private void ExecuteSendToBack(ArtemisDevice device) { SurfaceDeviceViewModel surfaceDeviceViewModel = SurfaceDeviceViewModels.First(d => d.Device == device); SurfaceDeviceViewModels.Move(SurfaceDeviceViewModels.IndexOf(surfaceDeviceViewModel), 0); for (int i = 0; i < SurfaceDeviceViewModels.Count; i++) { SurfaceDeviceViewModel deviceViewModel = SurfaceDeviceViewModels[i]; deviceViewModel.Device.ZIndex = i + 1; } ListDeviceViewModels.Sort(l => l.Device.ZIndex * -1); _rgbService.SaveDevices(); } private void ExecuteSendBackward(ArtemisDevice device) { SurfaceDeviceViewModel surfaceDeviceViewModel = SurfaceDeviceViewModels.First(d => d.Device == device); int currentIndex = SurfaceDeviceViewModels.IndexOf(surfaceDeviceViewModel); int newIndex = Math.Max(currentIndex - 1, 0); SurfaceDeviceViewModels.Move(currentIndex, newIndex); for (int i = 0; i < SurfaceDeviceViewModels.Count; i++) { SurfaceDeviceViewModel deviceViewModel = SurfaceDeviceViewModels[i]; deviceViewModel.Device.ZIndex = i + 1; } ListDeviceViewModels.Sort(l => l.Device.ZIndex * -1); _rgbService.SaveDevices(); } #endregion }