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

Migrations - Added migration to segments

Layout - Fixed rotation not always applying (workaround)
Conditions - Added string operators
This commit is contained in:
SpoinkyNL 2020-07-30 00:49:23 +02:00
parent dab11cb3e7
commit 385a30bec7
17 changed files with 317 additions and 22 deletions

View File

@ -34,6 +34,36 @@ namespace Artemis.Core.Models.Profile.Conditions
/// </summary> /// </summary>
public abstract string Icon { get; } public abstract string Icon { get; }
/// <summary>
/// Gets or sets whether this condition operator supports a right side, defaults to true
/// </summary>
public bool SupportsRightSide { get; protected set; } = true;
public bool SupportsType(Type type)
{
if (type == null)
return true;
return CompatibleTypes.Any(t => t.IsCastableFrom(type));
}
/// <summary>
/// Creates a binary expression comparing two types
/// </summary>
/// <param name="leftSide">The parameter on the left side of the expression</param>
/// <param name="rightSide">The parameter on the right side of the expression</param>
/// <returns></returns>
public abstract BinaryExpression CreateExpression(Expression leftSide, Expression rightSide);
/// <summary>
/// Returns an expression that checks the given expression for null
/// </summary>
/// <param name="expression"></param>
/// <returns></returns>
protected Expression CreateNullCheckExpression(Expression expression)
{
return Expression.NotEqual(expression, Expression.Constant(null));
}
internal void Register(PluginInfo pluginInfo, IDataModelService dataModelService) internal void Register(PluginInfo pluginInfo, IDataModelService dataModelService)
{ {
if (_registered) if (_registered)
@ -63,20 +93,5 @@ namespace Artemis.Core.Models.Profile.Conditions
// Profile editor service will call Unsubscribe // Profile editor service will call Unsubscribe
_dataModelService.RemoveConditionOperator(this); _dataModelService.RemoveConditionOperator(this);
} }
public bool SupportsType(Type type)
{
if (type == null)
return true;
return CompatibleTypes.Any(t => t.IsCastableFrom(type));
}
/// <summary>
/// Creates a binary expression comparing two types
/// </summary>
/// <param name="leftSide">The parameter on the left side of the expression</param>
/// <param name="rightSide">The parameter on the right side of the expression</param>
/// <returns></returns>
public abstract BinaryExpression CreateExpression(Expression leftSide, Expression rightSide);
} }
} }

View File

@ -304,7 +304,11 @@ namespace Artemis.Core.Models.Profile.Conditions
if (leftSideAccessor.Type.IsValueType && RightStaticValue == null) if (leftSideAccessor.Type.IsValueType && RightStaticValue == null)
return; return;
var rightSideConstant = Expression.Constant(RightStaticValue); // If the right side value is null, the constant type cannot be inferred and must be provided manually
var rightSideConstant = RightStaticValue != null
? Expression.Constant(RightStaticValue)
: Expression.Constant(null, leftSideAccessor.Type);
var conditionExpression = Operator.CreateExpression(leftSideAccessor, rightSideConstant); var conditionExpression = Operator.CreateExpression(leftSideAccessor, rightSideConstant);
StaticConditionLambda = Expression.Lambda<Func<DataModel, bool>>(conditionExpression, leftSideParameter); StaticConditionLambda = Expression.Lambda<Func<DataModel, bool>>(conditionExpression, leftSideParameter);

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace Artemis.Core.Models.Profile.Conditions.Operators
{
public class StringContainsConditionOperator : DisplayConditionOperator
{
private readonly MethodInfo _toLower;
private readonly MethodInfo _contains;
public StringContainsConditionOperator()
{
_toLower = typeof(string).GetMethod("ToLower", new Type[] { });
_contains = typeof(string).GetMethod("Contains", new[] {typeof(string) });
}
public override IReadOnlyCollection<Type> CompatibleTypes => new List<Type> {typeof(string)};
public override string Description => "Contains";
public override string Icon => "Contain";
public override BinaryExpression CreateExpression(Expression leftSide, Expression rightSide)
{
return Expression.Equal(Expression.Call(Expression.Call(leftSide, _toLower), _contains, Expression.Call(rightSide, _toLower)), Expression.Constant(true));
}
}
}

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace Artemis.Core.Models.Profile.Conditions.Operators
{
public class StringEndsWithConditionOperator : DisplayConditionOperator
{
private readonly MethodInfo _toLower;
private readonly MethodInfo _endsWith;
public StringEndsWithConditionOperator()
{
_toLower = typeof(string).GetMethod("ToLower", new Type[] { });
_endsWith = typeof(string).GetMethod("EndsWith", new[] { typeof(string) });
}
public override IReadOnlyCollection<Type> CompatibleTypes => new List<Type> { typeof(string) };
public override string Description => "Ends with";
public override string Icon => "ContainEnd";
public override BinaryExpression CreateExpression(Expression leftSide, Expression rightSide)
{
return Expression.Equal(Expression.Call(Expression.Call(leftSide, _toLower), _endsWith, Expression.Call(rightSide, _toLower)), Expression.Constant(true));
}
}
}

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace Artemis.Core.Models.Profile.Conditions.Operators
{
public class StringEqualsConditionOperator : DisplayConditionOperator
{
private readonly MethodInfo _toLower;
public StringEqualsConditionOperator()
{
_toLower = typeof(string).GetMethod("ToLower", new Type[] { });
}
public override IReadOnlyCollection<Type> CompatibleTypes => new List<Type> {typeof(string)};
public override string Description => "Equals";
public override string Icon => "Equal";
public override BinaryExpression CreateExpression(Expression leftSide, Expression rightSide)
{
return Expression.Equal(Expression.Call(leftSide, _toLower), Expression.Call(rightSide, _toLower));
}
}
}

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace Artemis.Core.Models.Profile.Conditions.Operators
{
public class StringNotContainsConditionOperator : DisplayConditionOperator
{
private readonly MethodInfo _toLower;
private readonly MethodInfo _contains;
public StringNotContainsConditionOperator()
{
_toLower = typeof(string).GetMethod("ToLower", new Type[] { });
_contains = typeof(string).GetMethod("Contains", new[] { typeof(string) });
}
public override IReadOnlyCollection<Type> CompatibleTypes => new List<Type> { typeof(string) };
public override string Description => "Does not contain";
public override string Icon => "FormatStrikethrough";
public override BinaryExpression CreateExpression(Expression leftSide, Expression rightSide)
{
return Expression.Equal(Expression.Call(Expression.Call(leftSide, _toLower), _contains, Expression.Call(rightSide, _toLower)), Expression.Constant(false));
}
}
}

View File

@ -0,0 +1,27 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace Artemis.Core.Models.Profile.Conditions.Operators
{
public class StringNotEqualConditionOperator : DisplayConditionOperator
{
private readonly MethodInfo _toLower;
public StringNotEqualConditionOperator()
{
_toLower = typeof(string).GetMethod("ToLower", new Type[] { });
}
public override IReadOnlyCollection<Type> CompatibleTypes => new List<Type> {typeof(string)};
public override string Description => "Does not equal";
public override string Icon => "NotEqualVariant";
public override BinaryExpression CreateExpression(Expression leftSide, Expression rightSide)
{
return Expression.NotEqual(Expression.Call(leftSide, _toLower), Expression.Call(rightSide, _toLower));
}
}
}

View File

@ -0,0 +1,24 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace Artemis.Core.Models.Profile.Conditions.Operators
{
public class StringNullConditionOperator : DisplayConditionOperator
{
public StringNullConditionOperator()
{
SupportsRightSide = false;
}
public override IReadOnlyCollection<Type> CompatibleTypes => new List<Type> {typeof(string)};
public override string Description => "Is null";
public override string Icon => "Null";
public override BinaryExpression CreateExpression(Expression leftSide, Expression rightSide)
{
return Expression.Equal(leftSide, Expression.Constant(null, leftSide.Type));
}
}
}

View File

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq.Expressions;
using System.Reflection;
namespace Artemis.Core.Models.Profile.Conditions.Operators
{
public class StringStartsWithConditionOperator : DisplayConditionOperator
{
private readonly MethodInfo _toLower;
private readonly MethodInfo _startsWith;
public StringStartsWithConditionOperator()
{
_toLower = typeof(string).GetMethod("ToLower", new Type[] { });
_startsWith = typeof(string).GetMethod("StartsWith", new[] { typeof(string) });
}
public override IReadOnlyCollection<Type> CompatibleTypes => new List<Type> { typeof(string) };
public override string Description => "Starts with";
public override string Icon => "ContainStart";
public override BinaryExpression CreateExpression(Expression leftSide, Expression rightSide)
{
return Expression.Equal(Expression.Call(Expression.Call(leftSide, _toLower), _startsWith, Expression.Call(rightSide, _toLower)), Expression.Constant(true));
}
}
}

View File

@ -134,10 +134,14 @@ namespace Artemis.Core.Models.Surface
internal void ApplyToRgbDevice() internal void ApplyToRgbDevice()
{ {
RgbDevice.Location = new Point(DeviceEntity.X, DeviceEntity.Y);
RgbDevice.Rotation = DeviceEntity.Rotation; RgbDevice.Rotation = DeviceEntity.Rotation;
RgbDevice.Scale = DeviceEntity.Scale; RgbDevice.Scale = DeviceEntity.Scale;
// Workaround for device rotation not applying
if (DeviceEntity.X == 0 && DeviceEntity.Y == 0)
RgbDevice.Location = new Point(1, 1);
RgbDevice.Location = new Point(DeviceEntity.X, DeviceEntity.Y);
CalculateRenderProperties(); CalculateRenderProperties();
OnDeviceUpdated(); OnDeviceUpdated();
} }

View File

@ -151,7 +151,21 @@ namespace Artemis.Core.Services
{ {
if (type == null) if (type == null)
return new List<DisplayConditionOperator>(_registeredConditionOperators); return new List<DisplayConditionOperator>(_registeredConditionOperators);
return _registeredConditionOperators.Where(c => c.CompatibleTypes.Any(t => t.IsCastableFrom(type))).ToList();
var candidates = _registeredConditionOperators.Where(c => c.CompatibleTypes.Any(t => t.IsCastableFrom(type))).ToList();
// If there are multiple operators with the same description, use the closest match
foreach (var displayConditionOperators in candidates.GroupBy(c => c.Description).Where(g => g.Count() > 1).ToList())
{
var bestCandidate = displayConditionOperators.OrderByDescending(c => c.CompatibleTypes.Contains(type)).FirstOrDefault();
foreach (var displayConditionOperator in displayConditionOperators)
{
if (displayConditionOperator != bestCandidate)
candidates.Remove(displayConditionOperator);
}
}
return candidates;
} }
} }
@ -162,12 +176,24 @@ namespace Artemis.Core.Services
private void RegisterBuiltInConditionOperators() private void RegisterBuiltInConditionOperators()
{ {
// General usage for any type
RegisterConditionOperator(Constants.CorePluginInfo, new EqualsConditionOperator()); RegisterConditionOperator(Constants.CorePluginInfo, new EqualsConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new NotEqualConditionOperator()); RegisterConditionOperator(Constants.CorePluginInfo, new NotEqualConditionOperator());
// Numeric operators
RegisterConditionOperator(Constants.CorePluginInfo, new LessThanConditionOperator()); RegisterConditionOperator(Constants.CorePluginInfo, new LessThanConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new GreaterThanConditionOperator()); RegisterConditionOperator(Constants.CorePluginInfo, new GreaterThanConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new LessThanOrEqualConditionOperator()); RegisterConditionOperator(Constants.CorePluginInfo, new LessThanOrEqualConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new GreaterThanOrEqualConditionOperator()); RegisterConditionOperator(Constants.CorePluginInfo, new GreaterThanOrEqualConditionOperator());
// String operators
RegisterConditionOperator(Constants.CorePluginInfo, new StringEqualsConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new StringNotEqualConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new StringContainsConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new StringNotContainsConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new StringStartsWithConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new StringEndsWithConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new StringNullConditionOperator());
} }
private void PluginServiceOnPluginEnabled(object sender, PluginEventArgs e) private void PluginServiceOnPluginEnabled(object sender, PluginEventArgs e)

View File

@ -0,0 +1,39 @@
using System;
using System.Linq;
using System.Runtime.InteropServices;
using Artemis.Storage.Entities.Profile;
using Artemis.Storage.Migrations.Interfaces;
using LiteDB;
namespace Artemis.Storage.Migrations
{
public class M4ProfileSegmentsMigration : IStorageMigration
{
public int UserVersion => 4;
public void Apply(LiteRepository repository)
{
var profiles = repository.Query<ProfileEntity>().ToList();
foreach (var profileEntity in profiles)
{
foreach (var folder in profileEntity.Folders.Where(f => f.MainSegmentLength == TimeSpan.Zero))
{
if (folder.PropertyEntities.Any(p => p.KeyframeEntities.Any()))
folder.MainSegmentLength = folder.PropertyEntities.Where(p => p.KeyframeEntities.Any()).Max(p => p.KeyframeEntities.Max(k => k.Position));
if (folder.MainSegmentLength == TimeSpan.Zero)
folder.MainSegmentLength = TimeSpan.FromSeconds(5);
}
foreach (var layer in profileEntity.Layers.Where(l => l.MainSegmentLength == TimeSpan.Zero))
{
if (layer.PropertyEntities.Any(p => p.KeyframeEntities.Any()))
layer.MainSegmentLength = layer.PropertyEntities.Where(p => p.KeyframeEntities.Any()).Max(p => p.KeyframeEntities.Max(k => k.Position));
if (layer.MainSegmentLength == TimeSpan.Zero)
layer.MainSegmentLength = TimeSpan.FromSeconds(5);
}
repository.Update(profileEntity);
}
}
}
}

View File

@ -12,7 +12,7 @@ namespace Artemis.Storage.Repositories
internal PluginRepository(LiteRepository repository) internal PluginRepository(LiteRepository repository)
{ {
_repository = repository; _repository = repository;
_repository.Database.GetCollection<PluginSettingEntity>().EnsureIndex(s => new {s.Name, s.PluginGuid}, true); _repository.Database.GetCollection<PluginSettingEntity>().EnsureIndex(s => new {s.Name, s.PluginGuid}, true);
} }

View File

@ -4,6 +4,7 @@ using System.Threading.Tasks;
using Artemis.Core.Models.Profile.Conditions; using Artemis.Core.Models.Profile.Conditions;
using Artemis.UI.Ninject.Factories; using Artemis.UI.Ninject.Factories;
using Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions.Abstract; using Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions.Abstract;
using Artemis.UI.Shared.Services.Interfaces;
using Humanizer; using Humanizer;
using Stylet; using Stylet;
@ -11,13 +12,15 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
{ {
public class DisplayConditionGroupViewModel : DisplayConditionViewModel public class DisplayConditionGroupViewModel : DisplayConditionViewModel
{ {
private readonly IProfileEditorService _profileEditorService;
private readonly IDisplayConditionsVmFactory _displayConditionsVmFactory; private readonly IDisplayConditionsVmFactory _displayConditionsVmFactory;
private bool _isRootGroup; private bool _isRootGroup;
private bool _isInitialized; private bool _isInitialized;
public DisplayConditionGroupViewModel(DisplayConditionGroup displayConditionGroup, DisplayConditionViewModel parent, IDisplayConditionsVmFactory displayConditionsVmFactory) : base( public DisplayConditionGroupViewModel(DisplayConditionGroup displayConditionGroup, DisplayConditionViewModel parent,
displayConditionGroup, parent) IProfileEditorService profileEditorService, IDisplayConditionsVmFactory displayConditionsVmFactory) : base(displayConditionGroup, parent)
{ {
_profileEditorService = profileEditorService;
_displayConditionsVmFactory = displayConditionsVmFactory; _displayConditionsVmFactory = displayConditionsVmFactory;
Execute.PostToUIThread(async () => Execute.PostToUIThread(async () =>
{ {
@ -55,13 +58,17 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
DisplayConditionGroup.AddChild(new DisplayConditionPredicate(DisplayConditionGroup, PredicateType.Static)); DisplayConditionGroup.AddChild(new DisplayConditionPredicate(DisplayConditionGroup, PredicateType.Static));
else if (type == "Dynamic") else if (type == "Dynamic")
DisplayConditionGroup.AddChild(new DisplayConditionPredicate(DisplayConditionGroup, PredicateType.Dynamic)); DisplayConditionGroup.AddChild(new DisplayConditionPredicate(DisplayConditionGroup, PredicateType.Dynamic));
Update(); Update();
_profileEditorService.UpdateSelectedProfileElement();
} }
public void AddGroup() public void AddGroup()
{ {
DisplayConditionGroup.AddChild(new DisplayConditionGroup(DisplayConditionGroup)); DisplayConditionGroup.AddChild(new DisplayConditionGroup(DisplayConditionGroup));
Update(); Update();
_profileEditorService.UpdateSelectedProfileElement();
} }
public override void Update() public override void Update()

View File

@ -254,6 +254,7 @@ namespace Artemis.UI.Screens
protected override void OnClose() protected override void OnClose()
{ {
SidebarViewModel.Dispose(); SidebarViewModel.Dispose();
// Lets force the GC to run after closing the window so it is obvious to users watching task manager // Lets force the GC to run after closing the window so it is obvious to users watching task manager
// that closing the UI will decrease the memory footprint of the application. // that closing the UI will decrease the memory footprint of the application.

View File

@ -197,6 +197,9 @@ namespace Artemis.UI.Screens.Sidebar
public void Dispose() public void Dispose()
{ {
var closeTask = CloseCurrentItem();
closeTask.Wait();
_pluginService.PluginEnabled -= PluginServiceOnPluginEnabled; _pluginService.PluginEnabled -= PluginServiceOnPluginEnabled;
_pluginService.PluginDisabled -= PluginServiceOnPluginDisabled; _pluginService.PluginDisabled -= PluginServiceOnPluginDisabled;
} }

View File

@ -38,8 +38,10 @@ namespace Artemis.Plugins.Modules.General
public void UpdateCurrentWindow() public void UpdateCurrentWindow()
{ {
var processId = WindowUtilities.GetActiveProcessId(); var processId = WindowUtilities.GetActiveProcessId();
if (DataModel.ActiveWindow == null || DataModel.ActiveWindow.Process.Id != processId) if (DataModel.ActiveWindow == null || DataModel.ActiveWindow.Process.Id != processId)
DataModel.ActiveWindow = new WindowDataModel(Process.GetProcessById(processId)); DataModel.ActiveWindow = new WindowDataModel(Process.GetProcessById(processId));
if (DataModel.ActiveWindow != null && string.IsNullOrWhiteSpace(DataModel.ActiveWindow.WindowTitle))
DataModel.ActiveWindow.WindowTitle = Process.GetProcessById(WindowUtilities.GetActiveProcessId()).MainWindowTitle;
} }
#endregion #endregion