From 6cad16ccd5757d6fd1bef8d76924041af8eac8f4 Mon Sep 17 00:00:00 2001 From: SpoinkyNL Date: Fri, 1 Apr 2016 22:30:57 +0200 Subject: [PATCH] Layer preview WIP (Also means actual drawing is being worked on) --- Artemis/Artemis/Artemis.csproj | 2 + .../KeyboardProviders/Razer/BlackWidow.cs | 16 +- Artemis/Artemis/Models/Profiles/LayerModel.cs | 52 +++-- .../Models/Profiles/LayerPropertiesModel.cs | 17 +- Artemis/Artemis/Utilities/ExtensionMethods.cs | 16 ++ Artemis/Artemis/Utilities/LayerDrawer.cs | 72 ++++--- Artemis/Artemis/Utilities/ValueConverters.cs | 39 ++++ .../ViewModels/LayerEditorViewModel.cs | 114 +++++++++- .../Views/LayerEditor/LayerConditionView.xaml | 8 +- Artemis/Artemis/Views/LayerEditorView.xaml | 203 ++++++++++++++++-- Artemis/Artemis/Views/ProfileEditorView.xaml | 2 +- 11 files changed, 448 insertions(+), 93 deletions(-) create mode 100644 Artemis/Artemis/Utilities/ValueConverters.cs diff --git a/Artemis/Artemis/Artemis.csproj b/Artemis/Artemis/Artemis.csproj index 6e1f6f181..1821266cc 100644 --- a/Artemis/Artemis/Artemis.csproj +++ b/Artemis/Artemis/Artemis.csproj @@ -188,6 +188,7 @@ True + @@ -397,6 +398,7 @@ + diff --git a/Artemis/Artemis/KeyboardProviders/Razer/BlackWidow.cs b/Artemis/Artemis/KeyboardProviders/Razer/BlackWidow.cs index 721b5f286..908f83fdb 100644 --- a/Artemis/Artemis/KeyboardProviders/Razer/BlackWidow.cs +++ b/Artemis/Artemis/KeyboardProviders/Razer/BlackWidow.cs @@ -1,10 +1,8 @@ -using System; -using System.Drawing; +using System.Drawing; using Artemis.KeyboardProviders.Razer.Utilities; using Corale.Colore.Core; -using Corale.Colore.Razer.Keyboard; -using ColoreColor = Corale.Colore.Core.Color; -using KeyboardCustom = Corale.Colore.Razer.Keyboard.Effects.Custom; +using Corale.Colore.Razer; +using Constants = Corale.Colore.Razer.Keyboard.Constants; namespace Artemis.KeyboardProviders.Razer { @@ -24,9 +22,9 @@ namespace Artemis.KeyboardProviders.Razer return false; // Some people have Synapse installed, but not a Chroma keyboard, deal with this - var blackWidowFound = Chroma.Instance.Query(Corale.Colore.Razer.Devices.Blackwidow).Connected; - var blackWidowTeFound = Chroma.Instance.Query(Corale.Colore.Razer.Devices.BlackwidowTe).Connected; - return (blackWidowFound || blackWidowTeFound); + var blackWidowFound = Chroma.Instance.Query(Devices.Blackwidow).Connected; + var blackWidowTeFound = Chroma.Instance.Query(Devices.BlackwidowTe).Connected; + return blackWidowFound || blackWidowTeFound; } public override void Enable() @@ -48,7 +46,7 @@ namespace Artemis.KeyboardProviders.Razer public override void DrawBitmap(Bitmap bitmap) { var razerArray = RazerUtilities.BitmapColorArray(bitmap, Height, Width); - + Chroma.Instance.Keyboard.SetCustom(razerArray); } } diff --git a/Artemis/Artemis/Models/Profiles/LayerModel.cs b/Artemis/Artemis/Models/Profiles/LayerModel.cs index 1f254544b..f5b479988 100644 --- a/Artemis/Artemis/Models/Profiles/LayerModel.cs +++ b/Artemis/Artemis/Models/Profiles/LayerModel.cs @@ -1,5 +1,5 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; +using System.ComponentModel; using System.Drawing; using System.Linq; using System.Windows.Media; @@ -24,7 +24,7 @@ namespace Artemis.Models.Profiles LayerConditions = new List(); LayerProperties = new List(); - _drawer = new LayerDrawer(this); + _drawer = new LayerDrawer(this, 4); } public string Name { get; set; } @@ -36,36 +36,41 @@ namespace Artemis.Models.Profiles public List LayerProperties { get; set; } [JsonIgnore] - public LayerPropertiesModel LayerCalculatedProperties { get; } + public LayerPropertiesModel LayerCalculatedProperties { get; set; } [JsonIgnore] - public ImageSource LayerImage => _drawer.GetPreviewImage(); + public ImageSource LayerImage => _drawer.GetThumbnail(); public bool ConditionsMet(IGameDataModel dataModel) { return LayerConditions.All(cm => cm.ConditionMet(dataModel)); } + public void DrawPreview(Graphics g) + { + if (LayerType == LayerType.KeyboardRectangle || LayerType == LayerType.KeyboardEllipse) + _drawer.Draw(g); + else if (LayerType == LayerType.KeyboardGif) + _drawer.DrawGif(g); + } + public void Draw(IGameDataModel dataModel, Graphics g) { if (!ConditionsMet(dataModel)) return; Update(dataModel); - switch (LayerType) - { - case LayerType.Folder: - DrawChildren(dataModel, g); - break; - case LayerType.Rectangle: - _drawer.DrawRectangle(g); - break; - case LayerType.Ellipse: - _drawer.DrawEllipse(g); - break; - default: - throw new ArgumentOutOfRangeException(); - } + + if (LayerType == LayerType.Folder) + DrawChildren(dataModel, g); + else if (LayerType == LayerType.KeyboardRectangle || LayerType == LayerType.KeyboardEllipse) + _drawer.Draw(g); + else if (LayerType == LayerType.KeyboardGif) + _drawer.DrawGif(g); + else if (LayerType == LayerType.Mouse) + _drawer.UpdateMouse(); + else if (LayerType == LayerType.Headset) + _drawer.UpdateHeadset(); } private void Update(IGameDataModel dataModel) @@ -84,8 +89,11 @@ namespace Artemis.Models.Profiles public enum LayerType { - Folder, - Rectangle, - Ellipse + [Description("Folder")] Folder, + [Description("Keyboard - Rectangle")] KeyboardRectangle, + [Description("Keyboard - Ellipse")] KeyboardEllipse, + [Description("Keyboard - GIF")] KeyboardGif, + [Description("Mouse")] Mouse, + [Description("Headset")] Headset } } \ No newline at end of file diff --git a/Artemis/Artemis/Models/Profiles/LayerPropertiesModel.cs b/Artemis/Artemis/Models/Profiles/LayerPropertiesModel.cs index 20e02df5f..709334f20 100644 --- a/Artemis/Artemis/Models/Profiles/LayerPropertiesModel.cs +++ b/Artemis/Artemis/Models/Profiles/LayerPropertiesModel.cs @@ -1,5 +1,6 @@ using System.Collections.Generic; -using System.Drawing; +using System.ComponentModel; +using System.Windows.Media; using System.Drawing.Drawing2D; namespace Artemis.Models.Profiles @@ -12,7 +13,7 @@ namespace Artemis.Models.Profiles public int Height { get; set; } public int Opacity { get; set; } public bool ContainedBrush { get; set; } - public LinearGradientMode GradientMode { get; set; } + public LayerColorMode ColorMode { get; set; } public bool Rotate { get; set; } public double RotateSpeed { get; set; } public List Colors { get; set; } @@ -22,4 +23,16 @@ namespace Artemis.Models.Profiles Colors = new List(); } } + + public enum LayerColorMode + { + [Description("Left to right")] + Horizontal, + [Description("Top to bottom")] + Vertical, + [Description("Shift")] + Shift, + [Description("Pulse")] + Pulse, + } } \ No newline at end of file diff --git a/Artemis/Artemis/Utilities/ExtensionMethods.cs b/Artemis/Artemis/Utilities/ExtensionMethods.cs index a5defa83d..afa91d147 100644 --- a/Artemis/Artemis/Utilities/ExtensionMethods.cs +++ b/Artemis/Artemis/Utilities/ExtensionMethods.cs @@ -4,9 +4,25 @@ namespace Artemis.Utilities { public static class ExtensionMethods { + #region String + + /// + /// Takes a string LikeThisOne and turns it into Like This One. + /// ZombieSheep - http://stackoverflow.com/a/5796793/5015269 + /// + /// + /// public static string SplitCamelCase(this string str) { return Regex.Replace(Regex.Replace(str, @"(\P{Ll})(\P{Ll}\p{Ll})", "$1 $2"), @"(\p{Ll})(\P{Ll})", "$1 $2"); } + + #endregion + + #region Color + + // TODO: Convert ColorHelpers to ExtensionMethods + + #endregion } } \ No newline at end of file diff --git a/Artemis/Artemis/Utilities/LayerDrawer.cs b/Artemis/Artemis/Utilities/LayerDrawer.cs index e37ec462f..bf57e04f8 100644 --- a/Artemis/Artemis/Utilities/LayerDrawer.cs +++ b/Artemis/Artemis/Utilities/LayerDrawer.cs @@ -13,33 +13,36 @@ namespace Artemis.Utilities internal class LayerDrawer { private readonly LayerModel _layerModel; + private LinearGradientBrush _brush; private Rectangle _rectangle; private double _rotationProgress; private Rectangle _userRectangle; - public LayerDrawer(LayerModel layerModel) + public LayerDrawer(LayerModel layerModel, int scale) { + Scale = scale; _layerModel = layerModel; _rotationProgress = 0; } - public void Draw(Graphics graphics) - { - _rectangle = new Rectangle( - _layerModel.LayerCalculatedProperties.X, - _layerModel.LayerCalculatedProperties.Y, - _layerModel.LayerCalculatedProperties.Width, - _layerModel.LayerCalculatedProperties.Height); - _userRectangle = new Rectangle( - _layerModel.LayerUserProperties.X, - _layerModel.LayerUserProperties.Y, - _layerModel.LayerUserProperties.Width, - _layerModel.LayerUserProperties.Height); + public int Scale { get; set; } - if (_layerModel.LayerType == LayerType.Ellipse) - DrawEllipse(graphics); - else if (_layerModel.LayerType == LayerType.Ellipse) - DrawRectangle(graphics); + public void Draw(Graphics g) + { + // Set up variables for this frame + _rectangle = new Rectangle(_layerModel.LayerCalculatedProperties.X*Scale, + _layerModel.LayerCalculatedProperties.Y*Scale, _layerModel.LayerCalculatedProperties.Width*Scale, + _layerModel.LayerCalculatedProperties.Height*Scale); + _userRectangle = new Rectangle(_layerModel.LayerUserProperties.X*Scale, + _layerModel.LayerUserProperties.Y*Scale, _layerModel.LayerUserProperties.Width*Scale, + _layerModel.LayerUserProperties.Height*Scale); + _brush = CreateGradientBrush( + _layerModel.LayerCalculatedProperties.Colors.Select(ColorHelpers.ToDrawingColor).ToList()); + + if (_layerModel.LayerType == LayerType.KeyboardRectangle) + DrawRectangle(g); + else if (_layerModel.LayerType == LayerType.KeyboardEllipse) + DrawEllipse(g); // Update the rotation progress _rotationProgress = _rotationProgress + _layerModel.LayerCalculatedProperties.RotateSpeed; @@ -50,23 +53,24 @@ namespace Artemis.Utilities _rotationProgress = _layerModel.LayerCalculatedProperties.RotateSpeed; } - public BitmapImage GetPreviewImage() + public BitmapImage GetThumbnail() { _rectangle = new Rectangle(0, 0, 18, 18); _userRectangle = new Rectangle(0, 0, 18, 18); _layerModel.LayerCalculatedProperties.Opacity = 255; - var brush = CreateGradientBrush(_layerModel.LayerUserProperties.Colors); + var brush = + CreateGradientBrush(_layerModel.LayerUserProperties.Colors.Select(ColorHelpers.ToDrawingColor).ToList()); var bitmap = new Bitmap(18, 18); using (var g = Graphics.FromImage(bitmap)) { g.SmoothingMode = SmoothingMode.AntiAlias; - if (_layerModel.LayerType == LayerType.Ellipse) + if (_layerModel.LayerType == LayerType.KeyboardEllipse) { g.FillEllipse(brush, _rectangle); g.DrawEllipse(new Pen(Color.Black, 1), 0, 0, 17, 17); } - else if (_layerModel.LayerType == LayerType.Rectangle) + else if (_layerModel.LayerType == LayerType.KeyboardRectangle) { g.FillRectangle(brush, _rectangle); g.DrawRectangle(new Pen(Color.Black, 1), 0, 0, 17, 17); @@ -90,11 +94,17 @@ namespace Artemis.Utilities } } - public void DrawRectangle(Graphics graphics) + public void DrawRectangle(Graphics g) { + g.FillRectangle(_brush, _rectangle); } - public void DrawEllipse(Graphics graphics) + public void DrawEllipse(Graphics g) + { + g.FillEllipse(_brush, _rectangle); + } + + public void DrawGif(Graphics g) { } @@ -152,8 +162,12 @@ namespace Artemis.Utilities ? new Rectangle(_rectangle.X, _rectangle.Y, _rectangle.Width, _rectangle.Height) : new Rectangle(_userRectangle.X, _userRectangle.Y, _userRectangle.Width, _userRectangle.Height); - return new LinearGradientBrush(rect, Color.Transparent, Color.Transparent, - _layerModel.LayerCalculatedProperties.GradientMode) + if (_layerModel.LayerCalculatedProperties.ColorMode == LayerColorMode.Horizontal) + return new LinearGradientBrush(rect, Color.Transparent, Color.Transparent, LinearGradientMode.Horizontal) + { + InterpolationColors = colorBlend + }; + return new LinearGradientBrush(rect, Color.Transparent, Color.Transparent, LinearGradientMode.Vertical) { InterpolationColors = colorBlend }; @@ -169,5 +183,13 @@ namespace Artemis.Utilities tilebleColors.Add(sourceColors.FirstOrDefault()); return tilebleColors; } + + public void UpdateMouse() + { + } + + public void UpdateHeadset() + { + } } } \ No newline at end of file diff --git a/Artemis/Artemis/Utilities/ValueConverters.cs b/Artemis/Artemis/Utilities/ValueConverters.cs new file mode 100644 index 000000000..766791568 --- /dev/null +++ b/Artemis/Artemis/Utilities/ValueConverters.cs @@ -0,0 +1,39 @@ +using System; +using System.ComponentModel; +using System.Globalization; +using System.Windows.Data; + +namespace Artemis.Utilities +{ + /// + /// Fredrik Hedblad - http://stackoverflow.com/a/3987099/5015269 + /// + public class EnumDescriptionConverter : IValueConverter + { + object IValueConverter.Convert(object value, Type targetType, object parameter, CultureInfo culture) + { + var myEnum = (Enum) value; + var description = GetEnumDescription(myEnum); + return description; + } + + object IValueConverter.ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) + { + return string.Empty; + } + + private string GetEnumDescription(Enum enumObj) + { + var fieldInfo = enumObj.GetType().GetField(enumObj.ToString()); + + var attribArray = fieldInfo.GetCustomAttributes(false); + + if (attribArray.Length == 0) + { + return enumObj.ToString(); + } + var attrib = attribArray[0] as DescriptionAttribute; + return attrib?.Description; + } + } +} \ No newline at end of file diff --git a/Artemis/Artemis/ViewModels/LayerEditorViewModel.cs b/Artemis/Artemis/ViewModels/LayerEditorViewModel.cs index 6532fa054..2d43aa8b8 100644 --- a/Artemis/Artemis/ViewModels/LayerEditorViewModel.cs +++ b/Artemis/Artemis/ViewModels/LayerEditorViewModel.cs @@ -1,29 +1,55 @@ -using System.Linq; +using System; +using System.Collections.Specialized; +using System.ComponentModel; +using System.Drawing; +using System.Drawing.Imaging; +using System.IO; +using System.Linq; +using System.Threading; +using System.Windows.Media; +using System.Windows.Media.Imaging; using Artemis.Models.Profiles; using Artemis.Utilities; using Artemis.ViewModels.LayerEditor; using Caliburn.Micro; +using Color = System.Windows.Media.Color; namespace Artemis.ViewModels { public class LayerEditorViewModel : Screen { + private readonly BackgroundWorker _previewWorker; private LayerModel _layer; + private LayerPropertiesModel _proposedProperties; public LayerEditorViewModel(LayerModel layer) { Layer = layer; + DataModelProps = new BindableCollection(); + ProposedColors = new BindableCollection(); + ProposedProperties = new LayerPropertiesModel(); + ProposedColors.CollectionChanged += UpdateColors; DataModelProps.AddRange(GeneralHelpers.GenerateTypeMap()); LayerConditionVms = new BindableCollection>( layer.LayerConditions.Select(c => new LayerConditionViewModel(this, c, DataModelProps))); - - ProposedProperties = new LayerPropertiesModel(); - GeneralHelpers.CopyProperties(ProposedProperties, Layer.LayerUserProperties); + + _previewWorker = new BackgroundWorker(); + _previewWorker.WorkerSupportsCancellation = true; + _previewWorker.DoWork += PreviewWorkerOnDoWork; + + _previewWorker.RunWorkerAsync(); + PreSelect(); } + public BindableCollection DataModelProps { get; set; } + + public BindableCollection LayerTypes => new BindableCollection(); + + public BindableCollection ProposedColors { get; set; } + public BindableCollection> LayerConditionVms { get; set; } public LayerModel Layer @@ -37,9 +63,66 @@ namespace Artemis.ViewModels } } - public BindableCollection DataModelProps { get; set; } + public LayerPropertiesModel ProposedProperties + { + get { return _proposedProperties; } + set + { + if (Equals(value, _proposedProperties)) return; + _proposedProperties = value; + NotifyOfPropertyChange(() => ProposedProperties); + } + } - public LayerPropertiesModel ProposedProperties { get; set; } + public ImageSource LayerImage + { + get + { + // For the preview, put the proposed properties into the calculated properties + _layer.LayerCalculatedProperties = ProposedProperties; + var bitmap = new Bitmap(ProposedProperties.Width, ProposedProperties.Height); + + using (var g = Graphics.FromImage(bitmap)) + { + _layer.DrawPreview(g); + } + + using (var memory = new MemoryStream()) + { + bitmap.Save(memory, ImageFormat.Png); + memory.Position = 0; + + var bitmapImage = new BitmapImage(); + bitmapImage.BeginInit(); + bitmapImage.StreamSource = memory; + bitmapImage.CacheOption = BitmapCacheOption.OnLoad; + bitmapImage.EndInit(); + + return bitmapImage; + } + } + } + + private void UpdateColors(object sender, NotifyCollectionChangedEventArgs e) + { + ProposedProperties.Colors = ProposedColors.ToList(); + } + + private void PreviewWorkerOnDoWork(object sender, DoWorkEventArgs doWorkEventArgs) + { + while (!_previewWorker.CancellationPending) + { + NotifyOfPropertyChange(() => LayerImage); + Thread.Sleep(1000/25); + } + } + + private void PreSelect() + { + GeneralHelpers.CopyProperties(ProposedProperties, Layer.LayerUserProperties); + ProposedColors.Clear(); + ProposedColors.AddRange(ProposedProperties.Colors); + } public void AddCondition() { @@ -48,15 +131,32 @@ namespace Artemis.ViewModels LayerConditionVms.Add(new LayerConditionViewModel(this, condition, DataModelProps)); } + public void AddColor() + { + ProposedColors.Add(ColorHelpers.ToMediaColor(ColorHelpers.GetRandomRainbowColor())); + } + + public void DeleteColor(Color c) + { + ProposedColors.Remove(c); + } + public void Apply() { GeneralHelpers.CopyProperties(Layer.LayerUserProperties, ProposedProperties); } - public void DeleteCondition(LayerConditionViewModel layerConditionViewModel, LayerConditionModel layerConditionModel) + public void DeleteCondition(LayerConditionViewModel layerConditionViewModel, + LayerConditionModel layerConditionModel) { LayerConditionVms.Remove(layerConditionViewModel); Layer.LayerConditions.Remove(layerConditionModel); } + + public override void CanClose(Action callback) + { + _previewWorker.CancelAsync(); + base.CanClose(callback); + } } } \ No newline at end of file diff --git a/Artemis/Artemis/Views/LayerEditor/LayerConditionView.xaml b/Artemis/Artemis/Views/LayerEditor/LayerConditionView.xaml index 621501fc9..c45b4fe19 100644 --- a/Artemis/Artemis/Views/LayerEditor/LayerConditionView.xaml +++ b/Artemis/Artemis/Views/LayerEditor/LayerConditionView.xaml @@ -22,7 +22,7 @@ - @@ -40,13 +40,13 @@ VerticalAlignment="Top" DisplayMemberPath="Display" /> - + - + - + + + + + + +