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

Profiles now associate themselves to keyboards using an identifier unique per model. Rendering no longer done on UI thread, fixing UI freezes (yes.. yes I did that)

This commit is contained in:
SpoinkyNL 2016-06-04 22:22:49 +02:00
parent 0033b8b982
commit 1ea471280b
21 changed files with 174 additions and 95 deletions

View File

@ -38,7 +38,7 @@ namespace Artemis.DAL
if (keyboard == null)
throw new ArgumentNullException(nameof(keyboard));
return GetAll().Where(g => g.GameName.Equals(game.Name) && g.KeyboardName.Equals(keyboard.Name)).ToList();
return GetAll().Where(g => g.GameName.Equals(game.Name) && g.KeyboardSlug.Equals(keyboard.Slug)).ToList();
}
/// <summary>
@ -50,10 +50,10 @@ namespace Artemis.DAL
{
if (prof == null)
throw new ArgumentNullException(nameof(prof));
if (!(prof.GameName?.Length > 1) || !(prof.KeyboardName?.Length > 1) || !(prof.Name?.Length > 1))
throw new ArgumentException("Profile is invalid. Name, GameName and KeyboardName are required");
if (!(prof.GameName?.Length > 1) || !(prof.KeyboardSlug?.Length > 1) || !(prof.Name?.Length > 1))
throw new ArgumentException("Profile is invalid. Name, GameName and KeyboardSlug are required");
var path = ProfileFolder + $@"\{prof.KeyboardName}\{prof.GameName}";
var path = ProfileFolder + $@"\{prof.KeyboardSlug}\{prof.GameName}";
if (!Directory.Exists(path))
Directory.CreateDirectory(path);
@ -84,7 +84,7 @@ namespace Artemis.DAL
using (var file = new StreamReader(path))
{
var prof = (ProfileModel)deserializer.Deserialize(file);
if (prof.GameName?.Length > 1 && prof.KeyboardName?.Length > 1 && prof.Name?.Length > 1)
if (prof.GameName?.Length > 1 && prof.KeyboardSlug?.Length > 1 && prof.Name?.Length > 1)
profiles.Add(prof);
}
}
@ -123,7 +123,7 @@ namespace Artemis.DAL
using (var file = new StreamReader(path))
{
var prof = (ProfileModel) deserializer.Deserialize(file);
if (!(prof.GameName?.Length > 1) || !(prof.KeyboardName?.Length > 1) || !(prof.Name?.Length > 1))
if (!(prof.GameName?.Length > 1) || !(prof.KeyboardSlug?.Length > 1) || !(prof.Name?.Length > 1))
return null;
return prof;
}
@ -159,7 +159,7 @@ namespace Artemis.DAL
return;
// Remove the old file
var path = ProfileFolder + $@"\{profile.KeyboardName}\{profile.GameName}\{profile.Name}.xml";
var path = ProfileFolder + $@"\{profile.KeyboardSlug}\{profile.GameName}\{profile.Name}.xml";
if (File.Exists(path))
File.Delete(path);
@ -171,7 +171,7 @@ namespace Artemis.DAL
public static void DeleteProfile(ProfileModel profile)
{
// Remove the file
var path = ProfileFolder + $@"\{profile.KeyboardName}\{profile.GameName}\{profile.Name}.xml";
var path = ProfileFolder + $@"\{profile.KeyboardSlug}\{profile.GameName}\{profile.Name}.xml";
if (File.Exists(path))
File.Delete(path);
}

View File

@ -42,13 +42,11 @@ namespace Artemis.DeviceProviders.Corsair
var leds = CueSDK.HeadsetSDK.Leds.Count();
var rect = new Rect(new Size(leds * 20, leds * 20));
var img = brush.Dispatcher.Invoke(() =>
{
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
c.DrawRectangle(brush, null, rect);
return ImageUtilities.DrawinVisualToBitmap(visual, rect);
});
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
c.DrawRectangle(brush, null, rect);
var img = ImageUtilities.DrawinVisualToBitmap(visual, rect);
var ledIndex = 0;
// Color each LED according to one of the pixels

View File

@ -42,13 +42,11 @@ namespace Artemis.DeviceProviders.Corsair
var leds = CueSDK.MouseSDK.Leds.Count();
var rect = new Rect(new Size(leds * 20, leds * 20));
var img = brush.Dispatcher.Invoke(() =>
{
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
c.DrawRectangle(brush, null, rect);
return ImageUtilities.DrawinVisualToBitmap(visual, rect);
});
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
c.DrawRectangle(brush, null, rect);
var img = ImageUtilities.DrawinVisualToBitmap(visual, rect);
var ledIndex = 0;
// Color each LED according to one of the pixels

View File

@ -72,7 +72,7 @@ namespace Artemis.DeviceProviders.Corsair
PreviewSettings = new PreviewSettings(665, 215, new Thickness(0, -5, 0, 0), Resources.strafe);
break;
}
Slug = "corsair-"+_keyboard.DeviceInfo.Model.Replace(' ', '-').ToLower();
_keyboard.Brush = _keyboardBrush ?? (_keyboardBrush = new ImageBrush());
}

View File

@ -14,6 +14,7 @@ namespace Artemis.DeviceProviders
}
public string Name { get; set; }
public string Slug { get; set; }
public int Height { get; set; }
public int Width { get; set; }
public string CantEnableText { get; set; }

View File

@ -13,6 +13,7 @@ namespace Artemis.DeviceProviders.Logitech
public Orion()
{
Name = "Logitech G910 RGB";
Slug = "logitech-g910";
CantEnableText = "Couldn't connect to your Logitech G910.\n" +
"Please check your cables and updating the Logitech Gaming Software\n" +
"A minimum version of 8.81.15 is required.\n\n" +

View File

@ -13,6 +13,7 @@ namespace Artemis.DeviceProviders.Razer
public BlackWidow()
{
Name = "Razer BlackWidow Chroma";
Slug = "razer-blackwidow-chroma";
CantEnableText = "Couldn't connect to your Razer BlackWidow Chroma.\n" +
"Please check your cables and try updating Razer Synapse.\n\n" +
"If needed, you can select a different keyboard in Artemis under settings.";

View File

@ -52,6 +52,7 @@ namespace Artemis.Models.Profiles
// Preview simply shows the properties as they are. When not previewing they are applied
LayerPropertiesModel appliedProperties;
Properties.Brush.Freeze();
if (!preview)
{
if (!ConditionsMet<T>(dataModel))
@ -97,10 +98,10 @@ namespace Artemis.Models.Profiles
{
if (!ConditionsMet<T>(dataModel))
return null; // Don't return the brush when not previewing and the conditions arent met
appliedProperties = Properties.Brush.Dispatcher.Invoke(() => Properties.GetAppliedProperties(dataModel));
appliedProperties = Properties.GetAppliedProperties(dataModel);
}
else
appliedProperties = Properties.Brush.Dispatcher.Invoke(() => GeneralHelpers.Clone(Properties));
appliedProperties = GeneralHelpers.Clone(Properties);
// TODO: Mouse/headset animations
// Update animations on layer types that support them

View File

@ -27,7 +27,7 @@ namespace Artemis.Models.Profiles
public string Name { get; set; }
public bool IsDefault { get; set; }
public string KeyboardName { get; set; }
public string KeyboardSlug { get; set; }
public string GameName { get; set; }
[XmlIgnore]
@ -36,7 +36,7 @@ namespace Artemis.Models.Profiles
protected bool Equals(ProfileModel other)
{
return string.Equals(Name, other.Name) &&
string.Equals(KeyboardName, other.KeyboardName) &&
string.Equals(KeyboardSlug, other.KeyboardSlug) &&
string.Equals(GameName, other.GameName);
}
@ -53,7 +53,7 @@ namespace Artemis.Models.Profiles
unchecked
{
var hashCode = Name?.GetHashCode() ?? 0;
hashCode = (hashCode*397) ^ (KeyboardName?.GetHashCode() ?? 0);
hashCode = (hashCode*397) ^ (KeyboardSlug?.GetHashCode() ?? 0);
hashCode = (hashCode*397) ^ (GameName?.GetHashCode() ?? 0);
return hashCode;
}
@ -69,27 +69,22 @@ namespace Artemis.Models.Profiles
public Bitmap GenerateBitmap<T>(Rect keyboardRect, IGameDataModel gameDataModel, bool preview,
bool updateAnimations)
{
Bitmap bitmap = null;
DrawingVisual.Dispatcher.Invoke(() =>
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
{
var visual = new DrawingVisual();
using (var c = visual.RenderOpen())
{
// Setup the DrawingVisual's size
c.PushClip(new RectangleGeometry(keyboardRect));
c.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, keyboardRect);
// Setup the DrawingVisual's size
c.PushClip(new RectangleGeometry(keyboardRect));
c.DrawRectangle(new SolidColorBrush(Color.FromArgb(0, 0, 0, 0)), null, keyboardRect);
// Draw the layers
foreach (var layerModel in Layers.OrderByDescending(l => l.Order))
layerModel.Draw<T>(gameDataModel, c, preview, updateAnimations);
// Draw the layers
foreach (var layerModel in Layers.OrderByDescending(l => l.Order))
layerModel.Draw<T>(gameDataModel, c, preview, updateAnimations);
// Remove the clip
c.Pop();
}
// Remove the clip
c.Pop();
}
bitmap = ImageUtilities.DrawinVisualToBitmap(visual, keyboardRect);
});
return bitmap;
return ImageUtilities.DrawinVisualToBitmap(visual, keyboardRect);
}
public Brush GenerateBrush<T>(IGameDataModel gameDataModel, LayerType type, bool preview, bool updateAnimations)

View File

@ -2,6 +2,7 @@ using System.Collections.Generic;
using System.Windows.Media;
using System.Xml.Serialization;
using Artemis.Models.Interfaces;
using Artemis.Utilities;
namespace Artemis.Models.Profiles.Properties
{
@ -15,6 +16,8 @@ namespace Artemis.Models.Profiles.Properties
[XmlInclude(typeof(FolderPropertiesModel))]
public abstract class LayerPropertiesModel
{
private Brush _brush;
protected LayerPropertiesModel()
{
Conditions = new List<LayerConditionModel>();
@ -23,6 +26,16 @@ namespace Artemis.Models.Profiles.Properties
public abstract LayerPropertiesModel GetAppliedProperties(IGameDataModel dataModel);
public List<LayerConditionModel> Conditions { get; set; }
public Brush Brush { get; set; }
public Brush Brush
{
get { return _brush; }
set
{
var cloned = value.Dispatcher.Invoke(() => GeneralHelpers.CloneAlt(value));
cloned.Freeze();
_brush = cloned;
}
}
}
}

View File

@ -5,6 +5,8 @@ using System.IO;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Windows;
using System.Windows.Markup;
using System.Xml;
using System.Xml.Serialization;
using Microsoft.Win32;
using static System.String;
@ -60,6 +62,25 @@ namespace Artemis.Utilities
}
}
/// <summary>
/// Perform a deep Copy of the object.
/// </summary>
/// <typeparam name="T">The type of object being copied.</typeparam>
/// <param name="source">The object instance to copy.</param>
/// <returns>The copied object.</returns>
public static T CloneAlt<T>(T source)
{
// Don't serialize a null object, simply return the default for that object
if (ReferenceEquals(source, null))
return default(T);
var xaml = XamlWriter.Save(source);
var xamlString = new StringReader(xaml);
var xmlTextReader = new XmlTextReader(xamlString);
var deepCopyObject = (T)XamlReader.Load(xmlTextReader);
return deepCopyObject;
}
public static string Serialize<T>(T source)
{
// Don't serialize a null object, simply return the default for that object

View File

@ -51,8 +51,7 @@ namespace Artemis.Utilities.Layers
}
var clip = new Rect(applied.X*scale, applied.Y*scale, applied.Width*scale, applied.Height*scale);
applied.Brush.Dispatcher.Invoke(() => DrawRectangle(c, applied, clip, rect, s1, s2));
DrawRectangle(c, applied, clip, rect, s1, s2);
}
private static void DrawRectangle(DrawingContext c, KeyboardPropertiesModel properties, Rect clip,

View File

@ -463,7 +463,7 @@ namespace Artemis.ViewModels.Profiles
if (name == null)
return;
if (name.Length < 1)
if (name.Length < 2)
{
DialogService.ShowMessageBox("Invalid profile name", "Please provide a valid profile name");
return;
@ -472,7 +472,7 @@ namespace Artemis.ViewModels.Profiles
var profile = new ProfileModel
{
Name = name,
KeyboardName = _mainManager.DeviceManager.ActiveKeyboard.Name,
KeyboardSlug = _mainManager.DeviceManager.ActiveKeyboard.Slug,
GameName = _gameModel.Name
};
@ -496,16 +496,24 @@ namespace Artemis.ViewModels.Profiles
return;
var oldName = SelectedProfile.Name;
SelectedProfile.Name =
await DialogService.ShowInputDialog("Rename profile", "Please enter a unique new profile name");
SelectedProfile.Name = await DialogService
.ShowInputDialog("Rename profile", "Please enter a unique new profile name");
// Null when the user cancelled
if (string.IsNullOrEmpty(SelectedProfile.Name) || SelectedProfile.Name.Length < 2)
{
SelectedProfile.Name = oldName;
return;
}
// Verify the name
while (ProfileProvider.GetAll().Contains(SelectedProfile))
{
SelectedProfile.Name =
await DialogService.ShowInputDialog("Name already in use", "Please enter a unique new profile name");
SelectedProfile.Name = await DialogService.
ShowInputDialog("Name already in use", "Please enter a unique new profile name");
// Null when the user cancelled
if (string.IsNullOrEmpty(SelectedProfile.Name))
if (string.IsNullOrEmpty(SelectedProfile.Name) || SelectedProfile.Name.Length < 2)
{
SelectedProfile.Name = oldName;
return;
@ -591,16 +599,16 @@ namespace Artemis.ViewModels.Profiles
}
// Verify the keyboard
if (profile.KeyboardName != _mainManager.DeviceManager.ActiveKeyboard.Name)
if (profile.KeyboardSlug != _mainManager.DeviceManager.ActiveKeyboard.Slug)
{
var adjustKeyboard = await DialogService.ShowQuestionMessageBox("Profile not inteded for this keyboard",
$"Watch out, this profile wasn't ment for this keyboard, but for the {profile.KeyboardName}. " +
$"Watch out, this profile wasn't ment for this keyboard, but for the {profile.KeyboardSlug}. " +
"You can still import it but you'll probably have to do some adjusting\n\n" +
"Continue?");
if (!adjustKeyboard.Value)
return;
profile.KeyboardName = _mainManager.DeviceManager.ActiveKeyboard.Name;
profile.KeyboardSlug = _mainManager.DeviceManager.ActiveKeyboard.Slug;
profile.IsDefault = false;
profile.FixBoundaries(_mainManager.DeviceManager.ActiveKeyboard.KeyboardRectangle(1));
}

View File

@ -87,37 +87,17 @@ namespace Artemis.ViewModels.Profiles
}
private void InvokeUpdateKeyboardPreview(object sender, ElapsedEventArgs e)
{
Application.Current.Dispatcher.InvokeAsync(UpdateKeyboardPreview, DispatcherPriority.ContextIdle);
}
public void Activate()
{
Activated = true;
PreviewTimer.Start();
}
public void Deactivate()
{
Activated = false;
PreviewTimer.Stop();
}
#region Drawing
/// <summary>
/// Generates a new image for the keyboard preview
/// </summary>
public void UpdateKeyboardPreview()
{
if (_blurProgress > 2)
_blurProgress = 0;
_blurProgress = _blurProgress + 0.025;
BlurRadius = (Math.Sin(_blurProgress*Math.PI) + 1)*10 + 10;
BlurRadius = (Math.Sin(_blurProgress * Math.PI) + 1) * 10 + 10;
if (SelectedProfile == null || _deviceManager.ActiveKeyboard == null)
{
KeyboardPreview = new DrawingImage();
var preview = new DrawingImage();
preview.Freeze();
KeyboardPreview = preview;
return;
}
@ -144,12 +124,12 @@ namespace Artemis.ViewModels.Profiles
if (accentColor == null)
return;
var pen = new Pen(new SolidColorBrush((Color) accentColor), 0.4);
var pen = new Pen(new SolidColorBrush((Color)accentColor), 0.4);
// Draw the selection outline and resize indicator
if (SelectedLayer != null && SelectedLayer.MustDraw())
{
var layerRect = ((KeyboardPropertiesModel) SelectedLayer.Properties).GetRect();
var layerRect = ((KeyboardPropertiesModel)SelectedLayer.Properties).GetRect();
// Deflate the rect so that the border is drawn on the inside
layerRect.Inflate(-0.2, -0.2);
@ -170,10 +150,22 @@ namespace Artemis.ViewModels.Profiles
// Remove the clip
drawingContext.Pop();
}
KeyboardPreview = new DrawingImage(visual.Drawing);
var drawnPreview = new DrawingImage(visual.Drawing);
drawnPreview.Freeze();
KeyboardPreview = drawnPreview;
}
#endregion
public void Activate()
{
Activated = true;
PreviewTimer.Start();
}
public void Deactivate()
{
Activated = false;
PreviewTimer.Stop();
}
#region Processing

View File

@ -1,4 +1,5 @@
using Artemis.Models.Interfaces;
using System.Windows.Media;
using Artemis.Models.Interfaces;
using Artemis.Models.Profiles.Properties;
using Artemis.Utilities;
@ -7,11 +8,24 @@ namespace Artemis.ViewModels.Profiles.Properties
public class HeadsetPropertiesViewModel : LayerPropertiesViewModel
{
private LayerPropertiesModel _proposedProperties;
private Brush _brush;
public HeadsetPropertiesViewModel(IGameDataModel gameDataModel, LayerPropertiesModel properties)
: base(gameDataModel)
{
ProposedProperties = GeneralHelpers.Clone(properties);
Brush = GeneralHelpers.CloneAlt(ProposedProperties.Brush);
}
public Brush Brush
{
get { return _brush; }
set
{
if (Equals(value, _brush)) return;
_brush = value;
NotifyOfPropertyChange(() => Brush);
}
}
public LayerPropertiesModel ProposedProperties
@ -27,7 +41,9 @@ namespace Artemis.ViewModels.Profiles.Properties
public override LayerPropertiesModel GetAppliedProperties()
{
return GeneralHelpers.Clone(ProposedProperties);
var properties = GeneralHelpers.Clone(ProposedProperties);
properties.Brush = Brush;
return properties;
}
}
}

View File

@ -1,4 +1,5 @@
using System.Windows.Forms;
using System.Windows.Media;
using Artemis.Models.Interfaces;
using Artemis.Models.Profiles.Properties;
using Artemis.Utilities;
@ -10,12 +11,14 @@ namespace Artemis.ViewModels.Profiles.Properties
{
private bool _isGif;
private KeyboardPropertiesModel _proposedProperties;
private Brush _brush;
public KeyboardPropertiesViewModel(IGameDataModel gameDataModel, LayerPropertiesModel properties)
: base(gameDataModel)
{
var keyboardProperties = (KeyboardPropertiesModel) properties;
ProposedProperties = GeneralHelpers.Clone(keyboardProperties);
Brush = GeneralHelpers.CloneAlt(ProposedProperties.Brush);
DataModelProps = new BindableCollection<GeneralHelpers.PropertyCollection>();
DataModelProps.AddRange(GeneralHelpers.GenerateTypeMap(gameDataModel));
@ -25,6 +28,7 @@ namespace Artemis.ViewModels.Profiles.Properties
OpacityProperties = new LayerDynamicPropertiesViewModel("Opacity", DataModelProps, keyboardProperties);
}
public KeyboardPropertiesModel ProposedProperties
{
get { return _proposedProperties; }
@ -77,7 +81,20 @@ namespace Artemis.ViewModels.Profiles.Properties
WidthProperties.Apply(ProposedProperties);
OpacityProperties.Apply(ProposedProperties);
return GeneralHelpers.Clone(ProposedProperties);
var properties = GeneralHelpers.Clone(ProposedProperties);
properties.Brush = Brush;
return properties;
}
public Brush Brush
{
get { return _brush; }
set
{
if (Equals(value, _brush)) return;
_brush = value;
NotifyOfPropertyChange(() => Brush);
}
}
}
}

View File

@ -1,4 +1,5 @@
using Artemis.Models.Interfaces;
using System.Windows.Media;
using Artemis.Models.Interfaces;
using Artemis.Models.Profiles.Properties;
using Caliburn.Micro;

View File

@ -1,4 +1,6 @@
using Artemis.Models.Interfaces;
using System.Windows.Media;
using System.Windows.Navigation;
using Artemis.Models.Interfaces;
using Artemis.Models.Profiles.Properties;
using Artemis.Utilities;
@ -7,11 +9,24 @@ namespace Artemis.ViewModels.Profiles.Properties
public class MousePropertiesViewModel : LayerPropertiesViewModel
{
private LayerPropertiesModel _proposedProperties;
private Brush _brush;
public MousePropertiesViewModel(IGameDataModel gameDataModel, LayerPropertiesModel properties)
: base(gameDataModel)
{
ProposedProperties = GeneralHelpers.Clone(properties);
Brush = GeneralHelpers.CloneAlt(ProposedProperties.Brush);
}
public Brush Brush
{
get { return _brush; }
set
{
if (Equals(value, _brush)) return;
_brush = value;
NotifyOfPropertyChange(() => Brush);
}
}
public LayerPropertiesModel ProposedProperties
@ -27,7 +42,9 @@ namespace Artemis.ViewModels.Profiles.Properties
public override LayerPropertiesModel GetAppliedProperties()
{
return GeneralHelpers.Clone(ProposedProperties);
var properties = GeneralHelpers.Clone(ProposedProperties);
properties.Brush = Brush;
return properties;
}
}
}

View File

@ -23,7 +23,7 @@
VerticalAlignment="Top" Height="18" Width="130" />
<Border Margin="10" BorderBrush="{StaticResource ControlBorderBrush}"
BorderThickness="1" SnapsToDevicePixels="True" ToolTip="Click to edit">
<ncore:ColorBox Brush="{Binding Path=ProposedProperties.Brush, Mode=TwoWay}" Height="24" Width="134" />
<ncore:ColorBox Brush="{Binding Path=Brush, Mode=TwoWay}" Height="24" Width="134" />
</Border>
</StackPanel>
<TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="4" Margin="10,2,10,10" FontSize="13.333"

View File

@ -74,7 +74,7 @@
VerticalAlignment="Top" Height="18" Width="130" />
<Border Margin="10" BorderBrush="{StaticResource ControlBorderBrush}"
BorderThickness="1" SnapsToDevicePixels="True" ToolTip="Click to edit">
<ncore:ColorBox Brush="{Binding Path=ProposedProperties.Brush, Mode=TwoWay}" Height="24" Width="134" />
<ncore:ColorBox Brush="{Binding Path=Brush, Mode=TwoWay}" Height="24" Width="134" />
</Border>
</StackPanel>

View File

@ -23,7 +23,7 @@
VerticalAlignment="Top" Height="18" Width="130" />
<Border Margin="10" BorderBrush="{StaticResource ControlBorderBrush}"
BorderThickness="1" SnapsToDevicePixels="True" ToolTip="Click to edit">
<ncore:ColorBox Brush="{Binding Path=ProposedProperties.Brush, Mode=TwoWay}" Height="24" Width="134" />
<ncore:ColorBox Brush="{Binding Path=Brush, Mode=TwoWay}" Height="24" Width="134" />
</Border>
</StackPanel>
<TextBlock Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="4" Margin="10,2,10,10" FontSize="13.333"