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>
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)
{
if (_registered)
@ -63,20 +93,5 @@ namespace Artemis.Core.Models.Profile.Conditions
// Profile editor service will call Unsubscribe
_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)
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);
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()
{
RgbDevice.Location = new Point(DeviceEntity.X, DeviceEntity.Y);
RgbDevice.Rotation = DeviceEntity.Rotation;
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();
OnDeviceUpdated();
}

View File

@ -151,7 +151,21 @@ namespace Artemis.Core.Services
{
if (type == null)
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()
{
// General usage for any type
RegisterConditionOperator(Constants.CorePluginInfo, new EqualsConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new NotEqualConditionOperator());
// Numeric operators
RegisterConditionOperator(Constants.CorePluginInfo, new LessThanConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new GreaterThanConditionOperator());
RegisterConditionOperator(Constants.CorePluginInfo, new LessThanOrEqualConditionOperator());
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)

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

View File

@ -254,6 +254,7 @@ namespace Artemis.UI.Screens
protected override void OnClose()
{
SidebarViewModel.Dispose();
// 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.

View File

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

View File

@ -38,8 +38,10 @@ namespace Artemis.Plugins.Modules.General
public void UpdateCurrentWindow()
{
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));
if (DataModel.ActiveWindow != null && string.IsNullOrWhiteSpace(DataModel.ActiveWindow.WindowTitle))
DataModel.ActiveWindow.WindowTitle = Process.GetProcessById(WindowUtilities.GetActiveProcessId()).MainWindowTitle;
}
#endregion