diff --git a/Artemis/Artemis/Managers/ModuleManager.cs b/Artemis/Artemis/Managers/ModuleManager.cs index 24992234f..f8903bc53 100644 --- a/Artemis/Artemis/Managers/ModuleManager.cs +++ b/Artemis/Artemis/Managers/ModuleManager.cs @@ -12,7 +12,6 @@ namespace Artemis.Managers { private readonly DeviceManager _deviceManager; private readonly ILogger _logger; - private ModuleModel _activeModule; private LoopManager _waitLoopManager; private ModuleModel _waitEffect; private readonly GeneralSettings _generalSettings; @@ -36,16 +35,7 @@ namespace Artemis.Managers public List Modules { get; set; } public List ProcessModules { get; set; } public List OverlayModules { get; set; } - - public ModuleModel ActiveModule - { - get { return _activeModule; } - private set - { - _activeModule = value; - RaiseEffectChangedEvent(new ModuleChangedEventArgs(value)); - } - } + public ModuleModel ActiveModule { get; private set; } public event EventHandler EffectChanged; @@ -130,14 +120,15 @@ namespace Artemis.Managers _logger.Debug("Starting LoopManager for module change"); loopManager.StartAsync(); } + + if (!ActiveModule.IsBoundToProcess && !ActiveModule.IsOverlay && storeAsLast) + { + _generalSettings.LastModule = ActiveModule?.Name; + _generalSettings.Save(); + } _logger.Debug("Changed active module to: {0}", moduleModel.Name); - - if (ActiveModule.IsBoundToProcess || ActiveModule.IsOverlay || !storeAsLast) - return; - // Regular modules are stored as the last active module - _generalSettings.LastModule = ActiveModule?.Name; - _generalSettings.Save(); + RaiseEffectChangedEvent(new ModuleChangedEventArgs(moduleModel)); } private void DeviceManagerOnOnKeyboardChanged(object sender, KeyboardChangedEventArgs e) diff --git a/Artemis/Artemis/Managers/ProfileManager.cs b/Artemis/Artemis/Managers/ProfileManager.cs index 1f7bd54d1..65660c4aa 100644 --- a/Artemis/Artemis/Managers/ProfileManager.cs +++ b/Artemis/Artemis/Managers/ProfileManager.cs @@ -46,7 +46,8 @@ namespace Artemis.Managers if (string.IsNullOrEmpty(_generalSettings.LastKeyboard) || _deviceManager.ChangingKeyboard) return; - var activePreview = PreviewViewModules.FirstOrDefault(vm => vm.IsActive && vm.UsesProfileEditor); + var activePreview = PreviewViewModules.FirstOrDefault( + vm => vm.IsActive && vm.UsesProfileEditor && vm.ModuleModel.Settings.IsEnabled); if (activePreview != null) EnsurePreviewActive(activePreview); else diff --git a/Artemis/Artemis/Modules/Abstract/ModuleViewModel.cs b/Artemis/Artemis/Modules/Abstract/ModuleViewModel.cs index ee241e78a..a1a6fd435 100644 --- a/Artemis/Artemis/Modules/Abstract/ModuleViewModel.cs +++ b/Artemis/Artemis/Modules/Abstract/ModuleViewModel.cs @@ -1,6 +1,7 @@ using Artemis.Events; using Artemis.Managers; using Artemis.Services; +using Artemis.Settings; using Artemis.ViewModels.Profiles; using Caliburn.Micro; using Ninject; @@ -15,14 +16,17 @@ namespace Artemis.Modules.Abstract private readonly MainManager _mainManager; private readonly IKernel _kernel; private ModuleSettings _settings; + private GeneralSettings _generalSettings; public ModuleViewModel(MainManager mainManager, ModuleModel moduleModel, IKernel kernel) { _mainManager = mainManager; _kernel = kernel; _moduleManager = mainManager.ModuleManager; + _generalSettings = DAL.SettingsProvider.Load(); ModuleModel = moduleModel; Settings = moduleModel.Settings; + _mainManager.EnabledChanged += MainManagerOnEnabledChanged; _moduleManager.EffectChanged += ModuleManagerOnModuleChanged; @@ -49,21 +53,33 @@ namespace Artemis.Modules.Abstract } public virtual bool IsModuleActive => _moduleManager.ActiveModule == ModuleModel; + + public virtual bool IsModuleEnabled + { + get + { + if (ModuleModel.IsBoundToProcess || ModuleModel.IsBoundToProcess) + return Settings.IsEnabled; + return _generalSettings.LastModule == ModuleModel.Name; + } + } + public abstract bool UsesProfileEditor { get; } private void MainManagerOnEnabledChanged(object sender, EnabledChangedEventArgs e) { + UpdatedEnabledSetting(); NotifyOfPropertyChange(() => IsModuleActive); - UpdateIsEnabled(); } private void ModuleManagerOnModuleChanged(object sender, ModuleChangedEventArgs e) { + UpdatedEnabledSetting(); NotifyOfPropertyChange(() => IsModuleActive); - UpdateIsEnabled(); + NotifyOfPropertyChange(() => IsModuleEnabled); } - private void UpdateIsEnabled() + private void UpdatedEnabledSetting() { if (ModuleModel.IsBoundToProcess || ModuleModel.IsOverlay) return; @@ -81,13 +97,20 @@ namespace Artemis.Modules.Abstract // On process-bound modules, only set the module model if (ModuleModel.IsBoundToProcess || ModuleModel.IsOverlay) + { + NotifyOfPropertyChange(() => IsModuleActive); + NotifyOfPropertyChange(() => IsModuleEnabled); return; + } // On other modules, activate them if necessary if (IsModuleActive && !Settings.IsEnabled) _moduleManager.ClearActiveModule(); else if (!IsModuleActive && Settings.IsEnabled) _moduleManager.ChangeActiveModule(ModuleModel, _mainManager.LoopManager); + + NotifyOfPropertyChange(() => IsModuleActive); + NotifyOfPropertyChange(() => IsModuleEnabled); } public virtual void SaveSettings() diff --git a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeView.xaml b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeView.xaml index 52f0ef258..fe03c3f47 100644 --- a/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeView.xaml +++ b/Artemis/Artemis/Modules/Games/CounterStrike/CounterStrikeView.xaml @@ -32,7 +32,7 @@ diff --git a/Artemis/Artemis/Modules/Games/Dota2/Dota2View.xaml b/Artemis/Artemis/Modules/Games/Dota2/Dota2View.xaml index 5a97a2651..8031e3691 100644 --- a/Artemis/Artemis/Modules/Games/Dota2/Dota2View.xaml +++ b/Artemis/Artemis/Modules/Games/Dota2/Dota2View.xaml @@ -32,7 +32,7 @@ diff --git a/Artemis/Artemis/Modules/Games/EurotruckSimulator2/EurotruckSimulator2View.xaml b/Artemis/Artemis/Modules/Games/EurotruckSimulator2/EurotruckSimulator2View.xaml index 46c6a1811..5be329411 100644 --- a/Artemis/Artemis/Modules/Games/EurotruckSimulator2/EurotruckSimulator2View.xaml +++ b/Artemis/Artemis/Modules/Games/EurotruckSimulator2/EurotruckSimulator2View.xaml @@ -51,7 +51,7 @@ diff --git a/Artemis/Artemis/Modules/Games/GtaV/GtaVView.xaml b/Artemis/Artemis/Modules/Games/GtaV/GtaVView.xaml index 8ae728f95..b5ca45e27 100644 --- a/Artemis/Artemis/Modules/Games/GtaV/GtaVView.xaml +++ b/Artemis/Artemis/Modules/Games/GtaV/GtaVView.xaml @@ -34,7 +34,7 @@ diff --git a/Artemis/Artemis/Modules/Games/LightFx/LightFxView.xaml b/Artemis/Artemis/Modules/Games/LightFx/LightFxView.xaml index eeed3ab8e..4a22f3531 100644 --- a/Artemis/Artemis/Modules/Games/LightFx/LightFxView.xaml +++ b/Artemis/Artemis/Modules/Games/LightFx/LightFxView.xaml @@ -36,11 +36,11 @@ - diff --git a/Artemis/Artemis/Modules/Games/Overwatch/OverwatchView.xaml b/Artemis/Artemis/Modules/Games/Overwatch/OverwatchView.xaml index d735fee8e..35916e0c7 100644 --- a/Artemis/Artemis/Modules/Games/Overwatch/OverwatchView.xaml +++ b/Artemis/Artemis/Modules/Games/Overwatch/OverwatchView.xaml @@ -45,11 +45,11 @@ - diff --git a/Artemis/Artemis/Modules/Games/ProjectCars/ProjectCarsView.xaml b/Artemis/Artemis/Modules/Games/ProjectCars/ProjectCarsView.xaml index cef09d6fc..944b85242 100644 --- a/Artemis/Artemis/Modules/Games/ProjectCars/ProjectCarsView.xaml +++ b/Artemis/Artemis/Modules/Games/ProjectCars/ProjectCarsView.xaml @@ -46,11 +46,11 @@ project by MikeyTT - diff --git a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueView.xaml b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueView.xaml index f34419489..c11bc6464 100644 --- a/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueView.xaml +++ b/Artemis/Artemis/Modules/Games/RocketLeague/RocketLeagueView.xaml @@ -32,7 +32,7 @@ diff --git a/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionView.xaml b/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionView.xaml index a73058315..92e3ac7e8 100644 --- a/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionView.xaml +++ b/Artemis/Artemis/Modules/Games/TheDivision/TheDivisionView.xaml @@ -33,7 +33,7 @@ diff --git a/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentView.xaml b/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentView.xaml index beaafe4a7..fcf0154aa 100644 --- a/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentView.xaml +++ b/Artemis/Artemis/Modules/Games/UnrealTournament/UnrealTournamentView.xaml @@ -29,11 +29,11 @@ - diff --git a/Artemis/Artemis/Modules/Games/Witcher3/Witcher3View.xaml b/Artemis/Artemis/Modules/Games/Witcher3/Witcher3View.xaml index a534a78b2..7243a8e37 100644 --- a/Artemis/Artemis/Modules/Games/Witcher3/Witcher3View.xaml +++ b/Artemis/Artemis/Modules/Games/Witcher3/Witcher3View.xaml @@ -27,11 +27,11 @@ - diff --git a/Artemis/Artemis/Modules/Games/WoW/WoWView.xaml b/Artemis/Artemis/Modules/Games/WoW/WoWView.xaml index 411c1ddd3..b6e24f40a 100644 --- a/Artemis/Artemis/Modules/Games/WoW/WoWView.xaml +++ b/Artemis/Artemis/Modules/Games/WoW/WoWView.xaml @@ -32,11 +32,11 @@ - diff --git a/Artemis/Artemis/Modules/General/Bubbles/BubblesView.xaml b/Artemis/Artemis/Modules/General/Bubbles/BubblesView.xaml index bbefe754e..ab1eca92d 100644 --- a/Artemis/Artemis/Modules/General/Bubbles/BubblesView.xaml +++ b/Artemis/Artemis/Modules/General/Bubbles/BubblesView.xaml @@ -39,7 +39,7 @@ diff --git a/Artemis/Artemis/Modules/General/GeneralProfile/GeneralProfileView.xaml b/Artemis/Artemis/Modules/General/GeneralProfile/GeneralProfileView.xaml index 465b42322..f6719e810 100644 --- a/Artemis/Artemis/Modules/General/GeneralProfile/GeneralProfileView.xaml +++ b/Artemis/Artemis/Modules/General/GeneralProfile/GeneralProfileView.xaml @@ -33,7 +33,7 @@ diff --git a/Artemis/Artemis/Modules/Overlays/OverlayProfile/OverlayProfileView.xaml b/Artemis/Artemis/Modules/Overlays/OverlayProfile/OverlayProfileView.xaml index 1d427a91c..3ee631a95 100644 --- a/Artemis/Artemis/Modules/Overlays/OverlayProfile/OverlayProfileView.xaml +++ b/Artemis/Artemis/Modules/Overlays/OverlayProfile/OverlayProfileView.xaml @@ -33,7 +33,7 @@ diff --git a/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs b/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs index ac40c4084..13afbfbd3 100644 --- a/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs +++ b/Artemis/Artemis/ViewModels/Profiles/ProfileEditorViewModel.cs @@ -69,7 +69,6 @@ namespace Artemis.ViewModels.Profiles _deviceManager.OnKeyboardChanged += DeviceManagerOnOnKeyboardChanged; _moduleModel.ProfileChanged += ModuleModelOnProfileChanged; LoadProfiles(); - ProfileViewModel.Activate(); _saveTimer = new Timer(5000); _saveTimer.Elapsed += ProfileSaveHandler; @@ -780,8 +779,7 @@ namespace Artemis.ViewModels.Profiles public void Dispose() { - ProfileViewModel.Deactivate(); - + ProfileViewModel.Dispose(); _saveTimer?.Stop(); _saveTimer?.Dispose(); _watcher?.Dispose(); diff --git a/Artemis/Artemis/ViewModels/Profiles/ProfileViewModel.cs b/Artemis/Artemis/ViewModels/Profiles/ProfileViewModel.cs index ff038d8ae..25dc25538 100644 --- a/Artemis/Artemis/ViewModels/Profiles/ProfileViewModel.cs +++ b/Artemis/Artemis/ViewModels/Profiles/ProfileViewModel.cs @@ -1,400 +1,390 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Windows; -using System.Windows.Controls; -using System.Windows.Input; -using System.Windows.Media; -using Artemis.Events; -using Artemis.Managers; -using Artemis.Modules.Abstract; -using Artemis.Profiles; -using Artemis.Profiles.Layers.Interfaces; -using Artemis.Profiles.Layers.Models; -using Artemis.Profiles.Layers.Types.Folder; -using Artemis.Properties; -using Artemis.Utilities; -using Caliburn.Micro; -using Castle.Components.DictionaryAdapter; -using MahApps.Metro; - -namespace Artemis.ViewModels.Profiles -{ - public class ProfileViewModel : PropertyChangedBase - { - private readonly DeviceManager _deviceManager; - private double _blurProgress; - private double _blurRadius; - private DateTime _downTime; - private LayerModel _draggingLayer; - private Point? _draggingLayerOffset; - private DrawingImage _keyboardPreview; - private Cursor _keyboardPreviewCursor; - private bool _resizing; - private LayerModel _selectedLayer; - private bool _showAll; - - public ProfileViewModel(DeviceManager deviceManager, LoopManager loopManager) - { - _deviceManager = deviceManager; - - ShowAll = false; - - loopManager.RenderCompleted += LoopManagerOnRenderCompleted; - deviceManager.OnKeyboardChanged += DeviceManagerOnOnKeyboardChanged; - } - - public ModuleModel ModuleModel { get; set; } - public ProfileModel SelectedProfile => ModuleModel?.ProfileModel; - - public LayerModel SelectedLayer - { - get { return _selectedLayer; } - set - { - if (Equals(value, _selectedLayer)) return; - _selectedLayer = value; - NotifyOfPropertyChange(() => SelectedLayer); - } - } - - public DrawingImage KeyboardPreview - { - get { return _keyboardPreview; } - set - { - if (Equals(value, _keyboardPreview)) return; - _keyboardPreview = value; - NotifyOfPropertyChange(() => KeyboardPreview); - } - } - - public double BlurRadius - { - get { return _blurRadius; } - set - { - if (value.Equals(_blurRadius)) return; - _blurRadius = value; - NotifyOfPropertyChange(() => BlurRadius); - } - } - - public bool ShowAll - { - get { return _showAll; } - set - { - if (value == _showAll) return; - _showAll = value; - NotifyOfPropertyChange(() => ShowAll); - } - } - - public ImageSource KeyboardImage => ImageUtilities - .BitmapToBitmapImage(_deviceManager.ActiveKeyboard?.PreviewSettings.Image ?? Resources.none); - - public bool Activated { get; set; } - - private void LoopManagerOnRenderCompleted(object sender, EventArgs eventArgs) - { - if (!Activated) - return; - - // Update the glowing effect around the keyboard - if (_blurProgress > 2) - _blurProgress = 0; - _blurProgress = _blurProgress + 0.025; - BlurRadius = (Math.Sin(_blurProgress * Math.PI) + 1) * 10 + 10; - - // Besides the usual checks, also check if the ActiveKeyboard isn't the NoneKeyboard - if (SelectedProfile == null || _deviceManager.ActiveKeyboard == null || - _deviceManager.ActiveKeyboard.Slug == "none") - { - var preview = new DrawingImage(); - preview.Freeze(); - KeyboardPreview = preview; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Windows; +using System.Windows.Controls; +using System.Windows.Input; +using System.Windows.Media; +using Artemis.Events; +using Artemis.Managers; +using Artemis.Modules.Abstract; +using Artemis.Profiles; +using Artemis.Profiles.Layers.Interfaces; +using Artemis.Profiles.Layers.Models; +using Artemis.Profiles.Layers.Types.Folder; +using Artemis.Properties; +using Artemis.Utilities; +using Caliburn.Micro; +using Castle.Components.DictionaryAdapter; +using MahApps.Metro; + +namespace Artemis.ViewModels.Profiles +{ + public class ProfileViewModel : PropertyChangedBase, IDisposable + { + private readonly DeviceManager _deviceManager; + private readonly LoopManager _loopManager; + private double _blurProgress; + private double _blurRadius; + private DateTime _downTime; + private LayerModel _draggingLayer; + private Point? _draggingLayerOffset; + private DrawingImage _keyboardPreview; + private Cursor _keyboardPreviewCursor; + private bool _resizing; + private LayerModel _selectedLayer; + private bool _showAll; + + public ProfileViewModel(DeviceManager deviceManager, LoopManager loopManager) + { + _deviceManager = deviceManager; + _loopManager = loopManager; + + ShowAll = false; + + _loopManager.RenderCompleted += LoopManagerOnRenderCompleted; + _deviceManager.OnKeyboardChanged += DeviceManagerOnOnKeyboardChanged; + } + + public ModuleModel ModuleModel { get; set; } + public ProfileModel SelectedProfile => ModuleModel?.ProfileModel; + + public LayerModel SelectedLayer + { + get { return _selectedLayer; } + set + { + if (Equals(value, _selectedLayer)) return; + _selectedLayer = value; + NotifyOfPropertyChange(() => SelectedLayer); + } + } + + public DrawingImage KeyboardPreview + { + get { return _keyboardPreview; } + set + { + if (Equals(value, _keyboardPreview)) return; + _keyboardPreview = value; + NotifyOfPropertyChange(() => KeyboardPreview); + } + } + + public double BlurRadius + { + get { return _blurRadius; } + set + { + if (value.Equals(_blurRadius)) return; + _blurRadius = value; + NotifyOfPropertyChange(() => BlurRadius); + } + } + + public bool ShowAll + { + get { return _showAll; } + set + { + if (value == _showAll) return; + _showAll = value; + NotifyOfPropertyChange(() => ShowAll); + } + } + + public ImageSource KeyboardImage => ImageUtilities + .BitmapToBitmapImage(_deviceManager.ActiveKeyboard?.PreviewSettings.Image ?? Resources.none); + + private void LoopManagerOnRenderCompleted(object sender, EventArgs eventArgs) + { + // Update the glowing effect around the keyboard + if (_blurProgress > 2) + _blurProgress = 0; + _blurProgress = _blurProgress + 0.025; + BlurRadius = (Math.Sin(_blurProgress * Math.PI) + 1) * 10 + 10; + + // Besides the usual checks, also check if the ActiveKeyboard isn't the NoneKeyboard + if (SelectedProfile == null || _deviceManager.ActiveKeyboard == null || _deviceManager.ActiveKeyboard.Slug == "none") + { + KeyboardPreview = null; // Setup layers for the next frame if (ModuleModel.IsInitialized) - ModuleModel.PreviewLayers = new List(); - - return; - } - - var renderLayers = GetRenderLayers(); - // Draw the current frame to the preview - var keyboardRect = _deviceManager.ActiveKeyboard.KeyboardRectangle(4); - var visual = new DrawingVisual(); - using (var drawingContext = visual.RenderOpen()) - { - // Setup the DrawingVisual's size - drawingContext.PushClip(new RectangleGeometry(keyboardRect)); - drawingContext.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, keyboardRect); - - // Draw the layers - foreach (var layer in renderLayers) - { - layer.Update(null, true, false); - if (layer.LayerType.ShowInEdtor) - layer.Draw(null, drawingContext, true, false); - } - - // Get the selection color - var accentColor = ThemeManager.DetectAppStyle(Application.Current)?.Item2?.Resources["AccentColor"]; - if (accentColor == null) - { - var preview = new DrawingImage(); - preview.Freeze(); - KeyboardPreview = preview; - return; - } - - var pen = new Pen(new SolidColorBrush((Color) accentColor), 0.4); - - // Draw the selection outline and resize indicator - if (SelectedLayer != null && SelectedLayer.MustDraw()) - { - var layerRect = SelectedLayer.Properties.PropertiesRect(); - // Deflate the rect so that the border is drawn on the inside - layerRect.Inflate(-0.2, -0.2); - - // Draw an outline around the selected layer - drawingContext.DrawRectangle(null, pen, layerRect); - // Draw a resize indicator in the bottom-right - drawingContext.DrawLine(pen, - new Point(layerRect.BottomRight.X - 1, layerRect.BottomRight.Y - 0.5), - new Point(layerRect.BottomRight.X - 1.2, layerRect.BottomRight.Y - 0.7)); - drawingContext.DrawLine(pen, - new Point(layerRect.BottomRight.X - 0.5, layerRect.BottomRight.Y - 1), - new Point(layerRect.BottomRight.X - 0.7, layerRect.BottomRight.Y - 1.2)); - drawingContext.DrawLine(pen, - new Point(layerRect.BottomRight.X - 0.5, layerRect.BottomRight.Y - 0.5), - new Point(layerRect.BottomRight.X - 0.7, layerRect.BottomRight.Y - 0.7)); - } - - SelectedProfile.RaiseDeviceDrawnEvent(new ProfileDeviceEventsArg(DrawType.Preview, null, true, drawingContext)); - - // Remove the clip - drawingContext.Pop(); - } - var drawnPreview = new DrawingImage(visual.Drawing); - drawnPreview.Freeze(); - KeyboardPreview = drawnPreview; - - // Setup layers for the next frame - if (ModuleModel.IsInitialized) - ModuleModel.PreviewLayers = renderLayers; - } - - private void DeviceManagerOnOnKeyboardChanged(object sender, KeyboardChangedEventArgs e) - { - NotifyOfPropertyChange(() => KeyboardImage); - } - - - public void Activate() - { - Activated = true; - } - - public void Deactivate() - { - Activated = false; - } - - #region Processing - - /// - /// Handler for clicking - /// - /// - public void MouseDownKeyboardPreview(MouseButtonEventArgs e) - { - if (e.LeftButton == MouseButtonState.Pressed) - _downTime = DateTime.Now; - } - - /// - /// Second handler for clicking, selects a the layer the user clicked on. - /// - /// - public void MouseUpKeyboardPreview(MouseButtonEventArgs e) - { - if (SelectedProfile == null || SelectedProfile.IsDefault) - return; - - var timeSinceDown = DateTime.Now - _downTime; - if (!(timeSinceDown.TotalMilliseconds < 500)) - return; - if (_draggingLayer != null) - return; - - var keyboard = _deviceManager.ActiveKeyboard; - var pos = e.GetPosition((Image) e.OriginalSource); - var x = pos.X / ((double) keyboard.PreviewSettings.Width / keyboard.Width); - var y = pos.Y / ((double) keyboard.PreviewSettings.Height / keyboard.Height); - - var hoverLayer = GetLayers().Where(l => l.MustDraw()) - .FirstOrDefault(l => l.Properties.PropertiesRect(1).Contains(x, y)); - - if (hoverLayer != null) - SelectedLayer = hoverLayer; - } - - /// - /// Handler for resizing and moving the currently selected layer - /// - /// - public void MouseMoveKeyboardPreview(MouseEventArgs e) - { - if (SelectedProfile == null) - return; - - var pos = e.GetPosition((Image) e.OriginalSource); - var keyboard = _deviceManager.ActiveKeyboard; - var x = pos.X / ((double) keyboard.PreviewSettings.Width / keyboard.Width); - var y = pos.Y / ((double) keyboard.PreviewSettings.Height / keyboard.Height); - var hoverLayer = GetLayers().Where(l => l.MustDraw()) - .FirstOrDefault(l => l.Properties.PropertiesRect(1).Contains(x, y)); - - HandleDragging(e, x, y, hoverLayer); - - if (hoverLayer == null) - { - KeyboardPreviewCursor = Cursors.Arrow; - return; - } - - // Turn the mouse pointer into a hand if hovering over an active layer - if (hoverLayer == SelectedLayer) - { - var rect = hoverLayer.Properties.PropertiesRect(1); - KeyboardPreviewCursor = - Math.Sqrt(Math.Pow(x - rect.BottomRight.X, 2) + Math.Pow(y - rect.BottomRight.Y, 2)) < 0.6 - ? Cursors.SizeNWSE - : Cursors.SizeAll; - } - else - { - KeyboardPreviewCursor = Cursors.Hand; - } - } - - public Cursor KeyboardPreviewCursor - { - get { return _keyboardPreviewCursor; } - set - { - if (Equals(value, _keyboardPreviewCursor)) return; - _keyboardPreviewCursor = value; - NotifyOfPropertyChange(() => KeyboardPreviewCursor); - } - } - - /// - /// Handles dragging the given layer - /// - /// - /// - /// - /// - private void HandleDragging(MouseEventArgs e, double x, double y, LayerModel hoverLayer) - { - // Reset the dragging state on mouse release - if (e.LeftButton == MouseButtonState.Released || - _draggingLayer != null && SelectedLayer != _draggingLayer) - { - _draggingLayerOffset = null; - _draggingLayer = null; - return; - } - - if (SelectedLayer == null || SelectedLayer.LayerType != null && !SelectedLayer.LayerType.ShowInEdtor) - return; - - // Setup the dragging state on mouse press - if (_draggingLayerOffset == null && hoverLayer != null && e.LeftButton == MouseButtonState.Pressed) - { - var layerRect = hoverLayer.Properties.PropertiesRect(1); - - _draggingLayerOffset = new Point(x - SelectedLayer.Properties.X, y - SelectedLayer.Properties.Y); - _draggingLayer = hoverLayer; - // Detect dragging if cursor is in the bottom right - _resizing = Math.Sqrt(Math.Pow(x - layerRect.BottomRight.X, 2) + - Math.Pow(y - layerRect.BottomRight.Y, 2)) < 0.6; - } - - if (_draggingLayerOffset == null || _draggingLayer == null || _draggingLayer != SelectedLayer) - return; - - var draggingProps = _draggingLayer.Properties; - // If no setup or reset was done, handle the actual dragging action - if (_resizing) - { - var newWidth = Math.Round(x - draggingProps.X); - var newHeight = Math.Round(y - draggingProps.Y); - - // Ensure the layer doesn't leave the canvas - if (newWidth < 1 || draggingProps.X + newWidth <= 0) - newWidth = draggingProps.Width; - if (newHeight < 1 || draggingProps.Y + newHeight <= 0) - newHeight = draggingProps.Height; - - draggingProps.Width = newWidth; - draggingProps.Height = newHeight; - } - else - { - var newX = Math.Round(x - _draggingLayerOffset.Value.X); - var newY = Math.Round(y - _draggingLayerOffset.Value.Y); - - // Ensure the layer doesn't leave the canvas - if (newX >= SelectedProfile.Width || newX + draggingProps.Width <= 0) - newX = draggingProps.X; - if (newY >= SelectedProfile.Height || newY + draggingProps.Height <= 0) - newY = draggingProps.Y; - - draggingProps.X = newX; - draggingProps.Y = newY; - } - } - - public List GetRenderLayers() - { - // Get the layers that must be drawn - List drawLayers; - if (ShowAll) - return SelectedProfile.GetRenderLayers(null, false, true); - - if (SelectedLayer == null || !SelectedLayer.Enabled) - return new EditableList(); - - if (SelectedLayer.LayerType is FolderType) - drawLayers = SelectedLayer.GetRenderLayers(null, false, true); - else - drawLayers = new List {SelectedLayer}; - - return drawLayers; - } - - - private List GetLayers() - { - if (ShowAll) - return SelectedProfile.GetLayers(); - if (SelectedLayer == null) - return new List(); - - lock (SelectedLayer) - { - // Get the layers that must be drawn - if (SelectedLayer.LayerType is FolderType) - return SelectedLayer.GetLayers().ToList(); - return new List {SelectedLayer}; - } - } - - #endregion - } + ModuleModel.PreviewLayers = new List(); + + return; + } + + var renderLayers = GetRenderLayers(); + // Draw the current frame to the preview + var keyboardRect = _deviceManager.ActiveKeyboard.KeyboardRectangle(4); + var visual = new DrawingVisual(); + using (var drawingContext = visual.RenderOpen()) + { + // Setup the DrawingVisual's size + drawingContext.PushClip(new RectangleGeometry(keyboardRect)); + drawingContext.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, keyboardRect); + + // Draw the layers + foreach (var layer in renderLayers) + { + layer.Update(null, true, false); + if (layer.LayerType.ShowInEdtor) + layer.Draw(null, drawingContext, true, false); + } + + // Get the selection color + var accentColor = ThemeManager.DetectAppStyle(Application.Current)?.Item2?.Resources["AccentColor"]; + if (accentColor == null) + { + var preview = new DrawingImage(); + preview.Freeze(); + KeyboardPreview = preview; + return; + } + + var pen = new Pen(new SolidColorBrush((Color) accentColor), 0.4); + + // Draw the selection outline and resize indicator + if (SelectedLayer != null && SelectedLayer.MustDraw()) + { + var layerRect = SelectedLayer.Properties.PropertiesRect(); + // Deflate the rect so that the border is drawn on the inside + layerRect.Inflate(-0.2, -0.2); + + // Draw an outline around the selected layer + drawingContext.DrawRectangle(null, pen, layerRect); + // Draw a resize indicator in the bottom-right + drawingContext.DrawLine(pen, + new Point(layerRect.BottomRight.X - 1, layerRect.BottomRight.Y - 0.5), + new Point(layerRect.BottomRight.X - 1.2, layerRect.BottomRight.Y - 0.7)); + drawingContext.DrawLine(pen, + new Point(layerRect.BottomRight.X - 0.5, layerRect.BottomRight.Y - 1), + new Point(layerRect.BottomRight.X - 0.7, layerRect.BottomRight.Y - 1.2)); + drawingContext.DrawLine(pen, + new Point(layerRect.BottomRight.X - 0.5, layerRect.BottomRight.Y - 0.5), + new Point(layerRect.BottomRight.X - 0.7, layerRect.BottomRight.Y - 0.7)); + } + + SelectedProfile.RaiseDeviceDrawnEvent(new ProfileDeviceEventsArg(DrawType.Preview, null, true, drawingContext)); + + // Remove the clip + drawingContext.Pop(); + } + var drawnPreview = new DrawingImage(visual.Drawing); + drawnPreview.Freeze(); + KeyboardPreview = drawnPreview; + + // Setup layers for the next frame + if (ModuleModel.IsInitialized) + ModuleModel.PreviewLayers = renderLayers; + } + + private void DeviceManagerOnOnKeyboardChanged(object sender, KeyboardChangedEventArgs e) + { + NotifyOfPropertyChange(() => KeyboardImage); + } + + #region Processing + + /// + /// Handler for clicking + /// + /// + public void MouseDownKeyboardPreview(MouseButtonEventArgs e) + { + if (e.LeftButton == MouseButtonState.Pressed) + _downTime = DateTime.Now; + } + + /// + /// Second handler for clicking, selects a the layer the user clicked on. + /// + /// + public void MouseUpKeyboardPreview(MouseButtonEventArgs e) + { + if (SelectedProfile == null || SelectedProfile.IsDefault) + return; + + var timeSinceDown = DateTime.Now - _downTime; + if (!(timeSinceDown.TotalMilliseconds < 500)) + return; + if (_draggingLayer != null) + return; + + var keyboard = _deviceManager.ActiveKeyboard; + var pos = e.GetPosition((Image) e.OriginalSource); + var x = pos.X / ((double) keyboard.PreviewSettings.Width / keyboard.Width); + var y = pos.Y / ((double) keyboard.PreviewSettings.Height / keyboard.Height); + + var hoverLayer = GetLayers().Where(l => l.MustDraw()) + .FirstOrDefault(l => l.Properties.PropertiesRect(1).Contains(x, y)); + + if (hoverLayer != null) + SelectedLayer = hoverLayer; + } + + /// + /// Handler for resizing and moving the currently selected layer + /// + /// + public void MouseMoveKeyboardPreview(MouseEventArgs e) + { + if (SelectedProfile == null) + return; + + var pos = e.GetPosition((Image) e.OriginalSource); + var keyboard = _deviceManager.ActiveKeyboard; + var x = pos.X / ((double) keyboard.PreviewSettings.Width / keyboard.Width); + var y = pos.Y / ((double) keyboard.PreviewSettings.Height / keyboard.Height); + var hoverLayer = GetLayers().Where(l => l.MustDraw()) + .FirstOrDefault(l => l.Properties.PropertiesRect(1).Contains(x, y)); + + HandleDragging(e, x, y, hoverLayer); + + if (hoverLayer == null) + { + KeyboardPreviewCursor = Cursors.Arrow; + return; + } + + // Turn the mouse pointer into a hand if hovering over an active layer + if (hoverLayer == SelectedLayer) + { + var rect = hoverLayer.Properties.PropertiesRect(1); + KeyboardPreviewCursor = + Math.Sqrt(Math.Pow(x - rect.BottomRight.X, 2) + Math.Pow(y - rect.BottomRight.Y, 2)) < 0.6 + ? Cursors.SizeNWSE + : Cursors.SizeAll; + } + else + { + KeyboardPreviewCursor = Cursors.Hand; + } + } + + public Cursor KeyboardPreviewCursor + { + get { return _keyboardPreviewCursor; } + set + { + if (Equals(value, _keyboardPreviewCursor)) return; + _keyboardPreviewCursor = value; + NotifyOfPropertyChange(() => KeyboardPreviewCursor); + } + } + + /// + /// Handles dragging the given layer + /// + /// + /// + /// + /// + private void HandleDragging(MouseEventArgs e, double x, double y, LayerModel hoverLayer) + { + // Reset the dragging state on mouse release + if (e.LeftButton == MouseButtonState.Released || + _draggingLayer != null && SelectedLayer != _draggingLayer) + { + _draggingLayerOffset = null; + _draggingLayer = null; + return; + } + + if (SelectedLayer == null || SelectedLayer.LayerType != null && !SelectedLayer.LayerType.ShowInEdtor) + return; + + // Setup the dragging state on mouse press + if (_draggingLayerOffset == null && hoverLayer != null && e.LeftButton == MouseButtonState.Pressed) + { + var layerRect = hoverLayer.Properties.PropertiesRect(1); + + _draggingLayerOffset = new Point(x - SelectedLayer.Properties.X, y - SelectedLayer.Properties.Y); + _draggingLayer = hoverLayer; + // Detect dragging if cursor is in the bottom right + _resizing = Math.Sqrt(Math.Pow(x - layerRect.BottomRight.X, 2) + + Math.Pow(y - layerRect.BottomRight.Y, 2)) < 0.6; + } + + if (_draggingLayerOffset == null || _draggingLayer == null || _draggingLayer != SelectedLayer) + return; + + var draggingProps = _draggingLayer.Properties; + // If no setup or reset was done, handle the actual dragging action + if (_resizing) + { + var newWidth = Math.Round(x - draggingProps.X); + var newHeight = Math.Round(y - draggingProps.Y); + + // Ensure the layer doesn't leave the canvas + if (newWidth < 1 || draggingProps.X + newWidth <= 0) + newWidth = draggingProps.Width; + if (newHeight < 1 || draggingProps.Y + newHeight <= 0) + newHeight = draggingProps.Height; + + draggingProps.Width = newWidth; + draggingProps.Height = newHeight; + } + else + { + var newX = Math.Round(x - _draggingLayerOffset.Value.X); + var newY = Math.Round(y - _draggingLayerOffset.Value.Y); + + // Ensure the layer doesn't leave the canvas + if (newX >= SelectedProfile.Width || newX + draggingProps.Width <= 0) + newX = draggingProps.X; + if (newY >= SelectedProfile.Height || newY + draggingProps.Height <= 0) + newY = draggingProps.Y; + + draggingProps.X = newX; + draggingProps.Y = newY; + } + } + + public List GetRenderLayers() + { + // Get the layers that must be drawn + List drawLayers; + if (ShowAll) + return SelectedProfile.GetRenderLayers(null, false, true); + + if (SelectedLayer == null || !SelectedLayer.Enabled) + return new EditableList(); + + if (SelectedLayer.LayerType is FolderType) + drawLayers = SelectedLayer.GetRenderLayers(null, false, true); + else + drawLayers = new List {SelectedLayer}; + + return drawLayers; + } + + + private List GetLayers() + { + if (ShowAll) + return SelectedProfile.GetLayers(); + if (SelectedLayer == null) + return new List(); + + lock (SelectedLayer) + { + // Get the layers that must be drawn + if (SelectedLayer.LayerType is FolderType) + return SelectedLayer.GetLayers().ToList(); + return new List {SelectedLayer}; + } + } + + public void Dispose() + { + _keyboardPreviewCursor?.Dispose(); + _loopManager.RenderCompleted -= LoopManagerOnRenderCompleted; + _deviceManager.OnKeyboardChanged -= DeviceManagerOnOnKeyboardChanged; + } + + #endregion + } } \ No newline at end of file