mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-31 09:43:46 +00:00
Profile editor - Redesigned adding/removing timeline segments
General module - Added some basic window information to the data model Profiles - Don't render when opacity is 0 Profile editor - Render non-selected layers in their main segment Profile editor - Condition editor fixes
This commit is contained in:
parent
527fef3dc6
commit
72d606f40d
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
|
using System.Windows.Interop;
|
||||||
using Artemis.Core.Plugins.Models;
|
using Artemis.Core.Plugins.Models;
|
||||||
|
|
||||||
namespace Artemis.Core
|
namespace Artemis.Core
|
||||||
@ -69,5 +70,7 @@ namespace Artemis.Core
|
|||||||
typeof(double),
|
typeof(double),
|
||||||
typeof(decimal)
|
typeof(decimal)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
public static IntPtr MainWindowHandle { get; internal set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1,20 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Artemis.Core.Events
|
|
||||||
{
|
|
||||||
public class PropertyGroupUpdatingEventArgs : EventArgs
|
|
||||||
{
|
|
||||||
public PropertyGroupUpdatingEventArgs(double deltaTime)
|
|
||||||
{
|
|
||||||
DeltaTime = deltaTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public PropertyGroupUpdatingEventArgs(TimeSpan overrideTime)
|
|
||||||
{
|
|
||||||
OverrideTime = overrideTime;
|
|
||||||
}
|
|
||||||
|
|
||||||
public double DeltaTime { get; }
|
|
||||||
public TimeSpan OverrideTime { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -159,7 +159,7 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
if (DisplayConditionPredicateEntity.LeftDataModelGuid != null)
|
if (DisplayConditionPredicateEntity.LeftDataModelGuid != null)
|
||||||
{
|
{
|
||||||
var dataModel = dataModelService.GetPluginDataModelByGuid(DisplayConditionPredicateEntity.LeftDataModelGuid.Value);
|
var dataModel = dataModelService.GetPluginDataModelByGuid(DisplayConditionPredicateEntity.LeftDataModelGuid.Value);
|
||||||
if (dataModel != null)
|
if (dataModel != null && dataModel.ContainsPath(DisplayConditionPredicateEntity.LeftPropertyPath))
|
||||||
UpdateLeftSide(dataModel, DisplayConditionPredicateEntity.LeftPropertyPath);
|
UpdateLeftSide(dataModel, DisplayConditionPredicateEntity.LeftPropertyPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -175,7 +175,7 @@ namespace Artemis.Core.Models.Profile.Conditions
|
|||||||
if (DisplayConditionPredicateEntity.RightDataModelGuid != null)
|
if (DisplayConditionPredicateEntity.RightDataModelGuid != null)
|
||||||
{
|
{
|
||||||
var dataModel = dataModelService.GetPluginDataModelByGuid(DisplayConditionPredicateEntity.RightDataModelGuid.Value);
|
var dataModel = dataModelService.GetPluginDataModelByGuid(DisplayConditionPredicateEntity.RightDataModelGuid.Value);
|
||||||
if (dataModel != null)
|
if (dataModel != null && dataModel.ContainsPath(DisplayConditionPredicateEntity.RightPropertyPath))
|
||||||
UpdateRightSide(dataModel, DisplayConditionPredicateEntity.RightPropertyPath);
|
UpdateRightSide(dataModel, DisplayConditionPredicateEntity.RightPropertyPath);
|
||||||
}
|
}
|
||||||
// Right side static
|
// Right side static
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using Artemis.Core.Models.Profile.LayerProperties;
|
|
||||||
using Artemis.Core.Plugins.LayerEffect.Abstract;
|
using Artemis.Core.Plugins.LayerEffect.Abstract;
|
||||||
using Artemis.Storage.Entities.Profile;
|
using Artemis.Storage.Entities.Profile;
|
||||||
using Artemis.Storage.Entities.Profile.Abstract;
|
using Artemis.Storage.Entities.Profile.Abstract;
|
||||||
@ -69,8 +68,15 @@ namespace Artemis.Core.Models.Profile
|
|||||||
|
|
||||||
UpdateDisplayCondition();
|
UpdateDisplayCondition();
|
||||||
|
|
||||||
|
// Update the layer timeline, this will give us a new delta time which could be negative in case the main segment wrapped back
|
||||||
|
// to it's start
|
||||||
|
var timelineDeltaTime = UpdateTimeline(deltaTime);
|
||||||
|
|
||||||
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
||||||
baseLayerEffect.Update(deltaTime);
|
{
|
||||||
|
baseLayerEffect.BaseProperties?.Update();
|
||||||
|
baseLayerEffect.Update(timelineDeltaTime);
|
||||||
|
}
|
||||||
|
|
||||||
// Iterate the children in reverse because that's how they must be rendered too
|
// Iterate the children in reverse because that's how they must be rendered too
|
||||||
for (var index = Children.Count - 1; index > -1; index--)
|
for (var index = Children.Count - 1; index > -1; index--)
|
||||||
@ -80,9 +86,49 @@ namespace Artemis.Core.Models.Profile
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override void OverrideProgress(TimeSpan timeOverride, bool stickToMainSegment)
|
||||||
|
{
|
||||||
|
if (!Enabled)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var beginTime = TimelinePosition;
|
||||||
|
|
||||||
|
if (stickToMainSegment)
|
||||||
|
{
|
||||||
|
if (!RepeatMainSegment)
|
||||||
|
{
|
||||||
|
var position = timeOverride + StartSegmentLength;
|
||||||
|
if (position > StartSegmentLength + EndSegmentLength)
|
||||||
|
TimelinePosition = StartSegmentLength + EndSegmentLength;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var progress = timeOverride.TotalMilliseconds % MainSegmentLength.TotalMilliseconds;
|
||||||
|
if (progress > 0)
|
||||||
|
TimelinePosition = TimeSpan.FromMilliseconds(progress) + StartSegmentLength;
|
||||||
|
else
|
||||||
|
TimelinePosition = StartSegmentLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
TimelinePosition = timeOverride;
|
||||||
|
|
||||||
|
var delta = (TimelinePosition - beginTime).TotalSeconds;
|
||||||
|
|
||||||
|
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
||||||
|
{
|
||||||
|
baseLayerEffect.BaseProperties?.Update();
|
||||||
|
baseLayerEffect.Update(delta);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo)
|
public override void Render(double deltaTime, SKCanvas canvas, SKImageInfo canvasInfo)
|
||||||
{
|
{
|
||||||
if (!Enabled || Path == null || !Children.Any(c => c.Enabled))
|
if (Path == null || !Enabled || !Children.Any(c => c.Enabled))
|
||||||
|
return;
|
||||||
|
|
||||||
|
// No need to render if at the end of the timeline
|
||||||
|
if (TimelinePosition > TimelineLength)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (_folderBitmap == null)
|
if (_folderBitmap == null)
|
||||||
@ -103,6 +149,10 @@ namespace Artemis.Core.Models.Profile
|
|||||||
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
||||||
baseLayerEffect.PreProcess(folderCanvas, _folderBitmap.Info, folderPath, folderPaint);
|
baseLayerEffect.PreProcess(folderCanvas, _folderBitmap.Info, folderPath, folderPaint);
|
||||||
|
|
||||||
|
// No point rendering if the alpha was set to zero by one of the effects
|
||||||
|
if (folderPaint.Color.Alpha == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
// Iterate the children in reverse because the first layer must be rendered last to end up on top
|
// Iterate the children in reverse because the first layer must be rendered last to end up on top
|
||||||
for (var index = Children.Count - 1; index > -1; index--)
|
for (var index = Children.Count - 1; index > -1; index--)
|
||||||
{
|
{
|
||||||
@ -176,6 +226,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
OnRenderPropertiesUpdated();
|
OnRenderPropertiesUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
internal override void ApplyToEntity()
|
internal override void ApplyToEntity()
|
||||||
{
|
{
|
||||||
FolderEntity.Id = EntityId;
|
FolderEntity.Id = EntityId;
|
||||||
@ -196,6 +247,16 @@ namespace Artemis.Core.Models.Profile
|
|||||||
DisplayConditionGroup?.ApplyToEntity();
|
DisplayConditionGroup?.ApplyToEntity();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal void Deactivate()
|
||||||
|
{
|
||||||
|
_folderBitmap?.Dispose();
|
||||||
|
_folderBitmap = null;
|
||||||
|
|
||||||
|
var layerEffects = new List<BaseLayerEffect>(LayerEffects);
|
||||||
|
foreach (var baseLayerEffect in layerEffects)
|
||||||
|
DeactivateLayerEffect(baseLayerEffect);
|
||||||
|
}
|
||||||
|
|
||||||
#region Events
|
#region Events
|
||||||
|
|
||||||
public event EventHandler RenderPropertiesUpdated;
|
public event EventHandler RenderPropertiesUpdated;
|
||||||
@ -206,15 +267,5 @@ namespace Artemis.Core.Models.Profile
|
|||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
internal void Deactivate()
|
|
||||||
{
|
|
||||||
_folderBitmap?.Dispose();
|
|
||||||
_folderBitmap = null;
|
|
||||||
|
|
||||||
var layerEffects = new List<BaseLayerEffect>(LayerEffects);
|
|
||||||
foreach (var baseLayerEffect in layerEffects)
|
|
||||||
DeactivateLayerEffect(baseLayerEffect);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -214,34 +214,66 @@ namespace Artemis.Core.Models.Profile
|
|||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override void Update(double deltaTime)
|
public override void Update(double deltaTime)
|
||||||
{
|
{
|
||||||
if (!Enabled)
|
if (!Enabled || LayerBrush?.BaseProperties == null || !LayerBrush.BaseProperties.PropertiesInitialized)
|
||||||
return;
|
|
||||||
|
|
||||||
if (LayerBrush?.BaseProperties == null || !LayerBrush.BaseProperties.PropertiesInitialized)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
// Ensure the layer must still be displayed
|
||||||
UpdateDisplayCondition();
|
UpdateDisplayCondition();
|
||||||
deltaTime = UpdateTimeline(deltaTime);
|
|
||||||
|
|
||||||
General.Update(deltaTime);
|
// TODO: No point updating further than this if the layer is not going to be rendered
|
||||||
Transform.Update(deltaTime);
|
|
||||||
LayerBrush.BaseProperties?.Update(deltaTime);
|
// Update the layer timeline, this will give us a new delta time which could be negative in case the main segment wrapped back
|
||||||
LayerBrush.Update(deltaTime);
|
// to it's start
|
||||||
|
var timelineDeltaTime = UpdateTimeline(deltaTime);
|
||||||
|
|
||||||
|
General.Update();
|
||||||
|
Transform.Update();
|
||||||
|
LayerBrush.BaseProperties?.Update();
|
||||||
|
LayerBrush.Update(timelineDeltaTime);
|
||||||
|
|
||||||
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
||||||
{
|
{
|
||||||
baseLayerEffect.BaseProperties?.Update(deltaTime);
|
baseLayerEffect.BaseProperties?.Update();
|
||||||
baseLayerEffect.Update(deltaTime);
|
baseLayerEffect.Update(timelineDeltaTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void OverrideProgress(TimeSpan timeOverride)
|
public override void OverrideProgress(TimeSpan timeOverride, bool stickToMainSegment)
|
||||||
{
|
{
|
||||||
General.Override(timeOverride);
|
if (!Enabled || LayerBrush?.BaseProperties == null || !LayerBrush.BaseProperties.PropertiesInitialized)
|
||||||
Transform.Override(timeOverride);
|
return;
|
||||||
LayerBrush?.BaseProperties?.Override(timeOverride);
|
|
||||||
foreach (var baseLayerEffect in LayerEffects)
|
var beginTime = TimelinePosition;
|
||||||
baseLayerEffect.BaseProperties?.Override(timeOverride);
|
|
||||||
|
if (stickToMainSegment)
|
||||||
|
{
|
||||||
|
if (!RepeatMainSegment)
|
||||||
|
{
|
||||||
|
var position = timeOverride + StartSegmentLength;
|
||||||
|
if (position > StartSegmentLength + EndSegmentLength)
|
||||||
|
TimelinePosition = StartSegmentLength + EndSegmentLength;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var progress = timeOverride.TotalMilliseconds % MainSegmentLength.TotalMilliseconds;
|
||||||
|
TimelinePosition = TimeSpan.FromMilliseconds(progress) + StartSegmentLength;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
TimelinePosition = timeOverride;
|
||||||
|
|
||||||
|
var delta = (TimelinePosition - beginTime).TotalSeconds;
|
||||||
|
|
||||||
|
General.Update();
|
||||||
|
Transform.Update();
|
||||||
|
LayerBrush.BaseProperties?.Update();
|
||||||
|
LayerBrush.Update(delta);
|
||||||
|
|
||||||
|
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
||||||
|
{
|
||||||
|
baseLayerEffect.BaseProperties?.Update();
|
||||||
|
baseLayerEffect.Update(delta);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
@ -280,6 +312,10 @@ namespace Artemis.Core.Models.Profile
|
|||||||
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
||||||
baseLayerEffect.PreProcess(layerCanvas, _layerBitmap.Info, layerPath, layerPaint);
|
baseLayerEffect.PreProcess(layerCanvas, _layerBitmap.Info, layerPath, layerPaint);
|
||||||
|
|
||||||
|
// No point rendering if the alpha was set to zero by one of the effects
|
||||||
|
if (layerPaint.Color.Alpha == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
layerCanvas.ClipPath(layerPath);
|
layerCanvas.ClipPath(layerPath);
|
||||||
|
|
||||||
if (!LayerBrush.SupportsTransformation)
|
if (!LayerBrush.SupportsTransformation)
|
||||||
|
|||||||
@ -65,11 +65,6 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsLoadedFromStorage { get; internal set; }
|
public bool IsLoadedFromStorage { get; internal set; }
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Gets the total progress on the timeline
|
|
||||||
/// </summary>
|
|
||||||
public TimeSpan TimelineProgress { get; internal set; }
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Used to declare that this property doesn't belong to a plugin and should use the core plugin GUID
|
/// Used to declare that this property doesn't belong to a plugin and should use the core plugin GUID
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@ -101,7 +101,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
|||||||
currentKeyframe.Value = value;
|
currentKeyframe.Value = value;
|
||||||
|
|
||||||
// Update the property so that the new keyframe is reflected on the current value
|
// Update the property so that the new keyframe is reflected on the current value
|
||||||
Update(0);
|
Update();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -184,17 +184,15 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates the property, moving the timeline forwards by the provided <paramref name="deltaTime" />
|
/// Updates the property, applying keyframes to the current value
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="deltaTime">The amount of time to move the timeline forwards</param>
|
internal void Update()
|
||||||
internal void Update(double deltaTime)
|
|
||||||
{
|
{
|
||||||
TimelineProgress = TimelineProgress.Add(TimeSpan.FromSeconds(deltaTime));
|
|
||||||
if (!KeyframesSupported || !KeyframesEnabled)
|
if (!KeyframesSupported || !KeyframesEnabled)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
// The current keyframe is the last keyframe before the current time
|
// The current keyframe is the last keyframe before the current time
|
||||||
CurrentKeyframe = _keyframes.LastOrDefault(k => k.Position <= TimelineProgress);
|
CurrentKeyframe = _keyframes.LastOrDefault(k => k.Position <= ProfileElement.TimelinePosition);
|
||||||
// Keyframes are sorted by position so we can safely assume the next keyframe's position is after the current
|
// Keyframes are sorted by position so we can safely assume the next keyframe's position is after the current
|
||||||
var nextIndex = _keyframes.IndexOf(CurrentKeyframe) + 1;
|
var nextIndex = _keyframes.IndexOf(CurrentKeyframe) + 1;
|
||||||
NextKeyframe = _keyframes.Count > nextIndex ? _keyframes[nextIndex] : null;
|
NextKeyframe = _keyframes.Count > nextIndex ? _keyframes[nextIndex] : null;
|
||||||
@ -208,7 +206,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var timeDiff = NextKeyframe.Position - CurrentKeyframe.Position;
|
var timeDiff = NextKeyframe.Position - CurrentKeyframe.Position;
|
||||||
var keyframeProgress = (float)((TimelineProgress - CurrentKeyframe.Position).TotalMilliseconds / timeDiff.TotalMilliseconds);
|
var keyframeProgress = (float)((ProfileElement.TimelinePosition - CurrentKeyframe.Position).TotalMilliseconds / timeDiff.TotalMilliseconds);
|
||||||
var keyframeProgressEased = (float)Easings.Interpolate(keyframeProgress, CurrentKeyframe.EasingFunction);
|
var keyframeProgressEased = (float)Easings.Interpolate(keyframeProgress, CurrentKeyframe.EasingFunction);
|
||||||
UpdateCurrentValue(keyframeProgress, keyframeProgressEased);
|
UpdateCurrentValue(keyframeProgress, keyframeProgressEased);
|
||||||
}
|
}
|
||||||
@ -216,16 +214,6 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
|||||||
OnUpdated();
|
OnUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// Overrides the timeline progress to match the provided <paramref name="overrideTime" />
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="overrideTime">The new progress to set the layer property timeline to.</param>
|
|
||||||
internal void OverrideProgress(TimeSpan overrideTime)
|
|
||||||
{
|
|
||||||
TimelineProgress = TimeSpan.Zero;
|
|
||||||
Update(overrideTime.TotalSeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Sorts the keyframes in ascending order by position
|
/// Sorts the keyframes in ascending order by position
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -242,8 +230,7 @@ namespace Artemis.Core.Models.Profile.LayerProperties
|
|||||||
|
|
||||||
PropertyEntity = entity;
|
PropertyEntity = entity;
|
||||||
LayerPropertyGroup = layerPropertyGroup;
|
LayerPropertyGroup = layerPropertyGroup;
|
||||||
LayerPropertyGroup.PropertyGroupUpdating += (sender, args) => Update(args.DeltaTime);
|
LayerPropertyGroup.PropertyGroupUpdating += (sender, args) => Update();
|
||||||
LayerPropertyGroup.PropertyGroupOverriding += (sender, args) => OverrideProgress(args.OverrideTime);
|
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
|||||||
@ -223,17 +223,11 @@ namespace Artemis.Core.Models.Profile
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal void Update(double deltaTime)
|
internal void Update()
|
||||||
{
|
{
|
||||||
// Since at this point we don't know what properties the group has without using reflection,
|
// Since at this point we don't know what properties the group has without using reflection,
|
||||||
// let properties subscribe to the update event and update themselves
|
// let properties subscribe to the update event and update themselves
|
||||||
OnPropertyGroupUpdating(new PropertyGroupUpdatingEventArgs(deltaTime));
|
OnPropertyGroupUpdating();
|
||||||
}
|
|
||||||
|
|
||||||
internal void Override(TimeSpan overrideTime)
|
|
||||||
{
|
|
||||||
// Same as above, but now the progress is overridden
|
|
||||||
OnPropertyGroupOverriding(new PropertyGroupUpdatingEventArgs(overrideTime));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void InitializeProperty(RenderProfileElement profileElement, string path, BaseLayerProperty instance)
|
private void InitializeProperty(RenderProfileElement profileElement, string path, BaseLayerProperty instance)
|
||||||
@ -260,8 +254,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
|
|
||||||
#region Events
|
#region Events
|
||||||
|
|
||||||
internal event EventHandler<PropertyGroupUpdatingEventArgs> PropertyGroupUpdating;
|
internal event EventHandler PropertyGroupUpdating;
|
||||||
internal event EventHandler<PropertyGroupUpdatingEventArgs> PropertyGroupOverriding;
|
|
||||||
public event EventHandler PropertyGroupInitialized;
|
public event EventHandler PropertyGroupInitialized;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -269,14 +262,9 @@ namespace Artemis.Core.Models.Profile
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public event EventHandler VisibilityChanged;
|
public event EventHandler VisibilityChanged;
|
||||||
|
|
||||||
internal virtual void OnPropertyGroupUpdating(PropertyGroupUpdatingEventArgs e)
|
protected virtual void OnPropertyGroupUpdating()
|
||||||
{
|
{
|
||||||
PropertyGroupUpdating?.Invoke(this, e);
|
PropertyGroupUpdating?.Invoke(this, EventArgs.Empty);
|
||||||
}
|
|
||||||
|
|
||||||
protected virtual void OnPropertyGroupOverriding(PropertyGroupUpdatingEventArgs e)
|
|
||||||
{
|
|
||||||
PropertyGroupOverriding?.Invoke(this, e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual void OnVisibilityChanged()
|
protected virtual void OnVisibilityChanged()
|
||||||
|
|||||||
@ -164,7 +164,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
public TimeSpan TimelinePosition
|
public TimeSpan TimelinePosition
|
||||||
{
|
{
|
||||||
get => _timelinePosition;
|
get => _timelinePosition;
|
||||||
private set => SetAndNotify(ref _timelinePosition, value);
|
protected set => SetAndNotify(ref _timelinePosition, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@ -212,13 +212,19 @@ namespace Artemis.Core.Models.Profile
|
|||||||
// Skip to the last segment if conditions are no longer met
|
// Skip to the last segment if conditions are no longer met
|
||||||
if (!AlwaysFinishTimeline && TimelinePosition < mainSegmentEnd)
|
if (!AlwaysFinishTimeline && TimelinePosition < mainSegmentEnd)
|
||||||
TimelinePosition = mainSegmentEnd;
|
TimelinePosition = mainSegmentEnd;
|
||||||
else if (TimelinePosition >= TimelineLength)
|
|
||||||
TimelinePosition = TimelineLength;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (TimelinePosition - oldPosition).TotalSeconds;
|
return (TimelinePosition - oldPosition).TotalSeconds;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Overrides the progress of the element
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="timeOverride"></param>
|
||||||
|
/// <param name="stickToMainSegment"></param>
|
||||||
|
public abstract void OverrideProgress(TimeSpan timeOverride, bool stickToMainSegment);
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Effects
|
#region Effects
|
||||||
|
|||||||
@ -34,5 +34,10 @@ namespace Artemis.Core.Plugins.Abstract.DataModels.Attributes
|
|||||||
/// Gets or sets an optional minimum value, this value is not enforced but used for percentage calculations.
|
/// Gets or sets an optional minimum value, this value is not enforced but used for percentage calculations.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public object MinValue { get; set; }
|
public object MinValue { get; set; }
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets whether this property resets the max depth of the data model, defaults to true
|
||||||
|
/// </summary>
|
||||||
|
public bool ResetsDepth { get; set; } = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -96,6 +96,12 @@ namespace Artemis.Core.Services
|
|||||||
OnInitialized();
|
OnInitialized();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public void SetMainWindowHandle(IntPtr handle)
|
||||||
|
{
|
||||||
|
Constants.MainWindowHandle = handle;
|
||||||
|
}
|
||||||
|
|
||||||
protected virtual void OnFrameRendering(FrameRenderingEventArgs e)
|
protected virtual void OnFrameRendering(FrameRenderingEventArgs e)
|
||||||
{
|
{
|
||||||
FrameRendering?.Invoke(this, e);
|
FrameRendering?.Invoke(this, e);
|
||||||
|
|||||||
@ -50,5 +50,11 @@ namespace Artemis.Core.Services.Interfaces
|
|||||||
/// Occurs whenever a frame is finished rendering and processed by RGB.NET
|
/// Occurs whenever a frame is finished rendering and processed by RGB.NET
|
||||||
/// </summary>
|
/// </summary>
|
||||||
event EventHandler<FrameRenderedEventArgs> FrameRendered;
|
event EventHandler<FrameRenderedEventArgs> FrameRendered;
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// To be called by the UI to setup the main window handle
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="handle"></param>
|
||||||
|
void SetMainWindowHandle(IntPtr handle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -167,7 +167,7 @@ namespace Artemis.UI.Shared.Controls
|
|||||||
private void Input_PreviewTextInput(object sender, TextCompositionEventArgs e)
|
private void Input_PreviewTextInput(object sender, TextCompositionEventArgs e)
|
||||||
{
|
{
|
||||||
var seperator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
|
var seperator = CultureInfo.CurrentCulture.NumberFormat.NumberDecimalSeparator;
|
||||||
var regex = new Regex("^[" + seperator + "][0-9]+$|^[0-9]*[" + seperator + "]{0,1}[0-9]*$");
|
var regex = new Regex("^[" + seperator + "][-|0-9]+$|^-?[0-9]*[" + seperator + "]{0,1}[0-9]*$");
|
||||||
e.Handled = !regex.IsMatch(e.Text);
|
e.Handled = !regex.IsMatch(e.Text);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -58,7 +58,7 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
|
|
||||||
foreach (var propertyInfo in ListType.GetProperties())
|
foreach (var propertyInfo in ListType.GetProperties())
|
||||||
{
|
{
|
||||||
var child = CreateChild(dataModelVisualizationService, propertyInfo);
|
var child = CreateChild(dataModelVisualizationService, propertyInfo, GetChildDepth());
|
||||||
if (child != null)
|
if (child != null)
|
||||||
Children.Add(child);
|
Children.Add(child);
|
||||||
}
|
}
|
||||||
|
|||||||
@ -35,6 +35,9 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
|
|
||||||
public override void Update(IDataModelVisualizationService dataModelVisualizationService)
|
public override void Update(IDataModelVisualizationService dataModelVisualizationService)
|
||||||
{
|
{
|
||||||
|
if (Parent != null && !Parent.IsVisualizationExpanded)
|
||||||
|
return;
|
||||||
|
|
||||||
List = GetCurrentValue() as IList;
|
List = GetCurrentValue() as IList;
|
||||||
if (List == null)
|
if (List == null)
|
||||||
return;
|
return;
|
||||||
|
|||||||
@ -13,7 +13,13 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
|
|
||||||
public override void Update(IDataModelVisualizationService dataModelVisualizationService)
|
public override void Update(IDataModelVisualizationService dataModelVisualizationService)
|
||||||
{
|
{
|
||||||
|
// Always populate properties
|
||||||
PopulateProperties(dataModelVisualizationService);
|
PopulateProperties(dataModelVisualizationService);
|
||||||
|
|
||||||
|
// Only update children if the parent is expanded
|
||||||
|
if (Parent != null && !Parent.IsVisualizationExpanded && !Parent.IsRootViewModel)
|
||||||
|
return;
|
||||||
|
|
||||||
foreach (var dataModelVisualizationViewModel in Children)
|
foreach (var dataModelVisualizationViewModel in Children)
|
||||||
dataModelVisualizationViewModel.Update(dataModelVisualizationService);
|
dataModelVisualizationViewModel.Update(dataModelVisualizationService);
|
||||||
}
|
}
|
||||||
@ -31,10 +37,15 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
var modelType = Parent.IsRootViewModel ? DataModel.GetType() : PropertyInfo.PropertyType;
|
var modelType = Parent.IsRootViewModel ? DataModel.GetType() : PropertyInfo.PropertyType;
|
||||||
foreach (var propertyInfo in modelType.GetProperties())
|
foreach (var propertyInfo in modelType.GetProperties())
|
||||||
{
|
{
|
||||||
var child = CreateChild(dataModelVisualizationService, propertyInfo);
|
var child = CreateChild(dataModelVisualizationService, propertyInfo, GetChildDepth());
|
||||||
if (child != null)
|
if (child != null)
|
||||||
Children.Add(child);
|
Children.Add(child);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected int GetChildDepth()
|
||||||
|
{
|
||||||
|
return PropertyDescription != null && !PropertyDescription.ResetsDepth ? Depth + 1 : 1;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -49,6 +49,9 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
|
|
||||||
public override void Update(IDataModelVisualizationService dataModelVisualizationService)
|
public override void Update(IDataModelVisualizationService dataModelVisualizationService)
|
||||||
{
|
{
|
||||||
|
if (Parent != null && !Parent.IsVisualizationExpanded && !Parent.IsRootViewModel)
|
||||||
|
return;
|
||||||
|
|
||||||
if (DisplayViewModel == null && dataModelVisualizationService.RegisteredDataModelDisplays.Any(d => d.SupportedType == PropertyInfo.PropertyType))
|
if (DisplayViewModel == null && dataModelVisualizationService.RegisteredDataModelDisplays.Any(d => d.SupportedType == PropertyInfo.PropertyType))
|
||||||
dataModelVisualizationService.GetDataModelDisplayViewModel(PropertyInfo.PropertyType);
|
dataModelVisualizationService.GetDataModelDisplayViewModel(PropertyInfo.PropertyType);
|
||||||
|
|
||||||
|
|||||||
@ -15,9 +15,11 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
{
|
{
|
||||||
public abstract class DataModelVisualizationViewModel : PropertyChangedBase
|
public abstract class DataModelVisualizationViewModel : PropertyChangedBase
|
||||||
{
|
{
|
||||||
|
private const int MaxDepth = 4;
|
||||||
private BindableCollection<DataModelVisualizationViewModel> _children;
|
private BindableCollection<DataModelVisualizationViewModel> _children;
|
||||||
private DataModel _dataModel;
|
private DataModel _dataModel;
|
||||||
private bool _isMatchingFilteredTypes;
|
private bool _isMatchingFilteredTypes;
|
||||||
|
private bool _isVisualizationExpanded;
|
||||||
private DataModelVisualizationViewModel _parent;
|
private DataModelVisualizationViewModel _parent;
|
||||||
private DataModelPropertyAttribute _propertyDescription;
|
private DataModelPropertyAttribute _propertyDescription;
|
||||||
private PropertyInfo _propertyInfo;
|
private PropertyInfo _propertyInfo;
|
||||||
@ -37,6 +39,7 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
}
|
}
|
||||||
|
|
||||||
public bool IsRootViewModel { get; }
|
public bool IsRootViewModel { get; }
|
||||||
|
public int Depth { get; set; }
|
||||||
|
|
||||||
public DataModel DataModel
|
public DataModel DataModel
|
||||||
{
|
{
|
||||||
@ -74,6 +77,16 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
set => SetAndNotify(ref _isMatchingFilteredTypes, value);
|
set => SetAndNotify(ref _isMatchingFilteredTypes, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsVisualizationExpanded
|
||||||
|
{
|
||||||
|
get => _isVisualizationExpanded;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (!SetAndNotify(ref _isVisualizationExpanded, value)) return;
|
||||||
|
RequestUpdate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public string PropertyPath
|
public string PropertyPath
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
@ -104,11 +117,26 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Updates the datamodel and if in an parent, any children
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="dataModelVisualizationService"></param>
|
||||||
public abstract void Update(IDataModelVisualizationService dataModelVisualizationService);
|
public abstract void Update(IDataModelVisualizationService dataModelVisualizationService);
|
||||||
|
|
||||||
public virtual object GetCurrentValue()
|
public virtual object GetCurrentValue()
|
||||||
{
|
{
|
||||||
return Parent == null ? null : PropertyInfo.GetValue(Parent.GetCurrentValue());
|
try
|
||||||
|
{
|
||||||
|
if (PropertyInfo.GetGetMethod() == null)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return Parent == null ? null : PropertyInfo.GetValue(Parent.GetCurrentValue());
|
||||||
|
}
|
||||||
|
catch (Exception)
|
||||||
|
{
|
||||||
|
// ignored, who knows what kind of shit can go wrong here...
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ApplyTypeFilter(bool looseMatch, params Type[] filteredTypes)
|
public void ApplyTypeFilter(bool looseMatch, params Type[] filteredTypes)
|
||||||
@ -157,6 +185,7 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
{
|
{
|
||||||
if (predicate.LeftDataModel == null || predicate.LeftPropertyPath == null)
|
if (predicate.LeftDataModel == null || predicate.LeftPropertyPath == null)
|
||||||
return null;
|
return null;
|
||||||
|
|
||||||
return GetChildByPath(predicate.LeftDataModel.PluginInfo.Guid, predicate.LeftPropertyPath);
|
return GetChildByPath(predicate.LeftDataModel.PluginInfo.Guid, predicate.LeftPropertyPath);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,6 +196,14 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
|
|
||||||
public DataModelVisualizationViewModel GetChildByPath(Guid dataModelGuid, string propertyPath)
|
public DataModelVisualizationViewModel GetChildByPath(Guid dataModelGuid, string propertyPath)
|
||||||
{
|
{
|
||||||
|
// Ensure children are populated by requesting an update
|
||||||
|
if (!IsVisualizationExpanded)
|
||||||
|
{
|
||||||
|
IsVisualizationExpanded = true;
|
||||||
|
RequestUpdate();
|
||||||
|
IsVisualizationExpanded = false;
|
||||||
|
}
|
||||||
|
|
||||||
var path = propertyPath.Split(".");
|
var path = propertyPath.Split(".");
|
||||||
var currentPart = path.First();
|
var currentPart = path.First();
|
||||||
|
|
||||||
@ -187,8 +224,10 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected DataModelVisualizationViewModel CreateChild(IDataModelVisualizationService dataModelVisualizationService, PropertyInfo propertyInfo)
|
protected DataModelVisualizationViewModel CreateChild(IDataModelVisualizationService dataModelVisualizationService, PropertyInfo propertyInfo, int depth)
|
||||||
{
|
{
|
||||||
|
if (depth > MaxDepth)
|
||||||
|
return null;
|
||||||
// Skip properties decorated with DataModelIgnore
|
// Skip properties decorated with DataModelIgnore
|
||||||
if (Attribute.IsDefined(propertyInfo, typeof(DataModelIgnoreAttribute)))
|
if (Attribute.IsDefined(propertyInfo, typeof(DataModelIgnoreAttribute)))
|
||||||
return null;
|
return null;
|
||||||
@ -196,19 +235,36 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
// If a display VM was found, prefer to use that in any case
|
// If a display VM was found, prefer to use that in any case
|
||||||
var typeViewModel = dataModelVisualizationService.GetDataModelDisplayViewModel(propertyInfo.PropertyType);
|
var typeViewModel = dataModelVisualizationService.GetDataModelDisplayViewModel(propertyInfo.PropertyType);
|
||||||
if (typeViewModel != null)
|
if (typeViewModel != null)
|
||||||
return new DataModelPropertyViewModel(DataModel, this, propertyInfo) {DisplayViewModel = typeViewModel};
|
return new DataModelPropertyViewModel(DataModel, this, propertyInfo) {DisplayViewModel = typeViewModel, Depth = depth};
|
||||||
// For primitives, create a property view model, it may be null that is fine
|
// For primitives, create a property view model, it may be null that is fine
|
||||||
if (propertyInfo.PropertyType.IsPrimitive || propertyInfo.PropertyType == typeof(string))
|
if (propertyInfo.PropertyType.IsPrimitive || propertyInfo.PropertyType == typeof(string))
|
||||||
return new DataModelPropertyViewModel(DataModel, this, propertyInfo);
|
return new DataModelPropertyViewModel(DataModel, this, propertyInfo) {Depth = depth};
|
||||||
if (typeof(IList).IsAssignableFrom(propertyInfo.PropertyType))
|
if (typeof(IList).IsAssignableFrom(propertyInfo.PropertyType))
|
||||||
return new DataModelListViewModel(DataModel, this, propertyInfo);
|
return new DataModelListViewModel(DataModel, this, propertyInfo) {Depth = depth};
|
||||||
// For other value types create a child view model
|
// For other value types create a child view model
|
||||||
if (propertyInfo.PropertyType.IsClass || propertyInfo.PropertyType.IsStruct())
|
if (propertyInfo.PropertyType.IsClass || propertyInfo.PropertyType.IsStruct())
|
||||||
return new DataModelPropertiesViewModel(DataModel, this, propertyInfo);
|
return new DataModelPropertiesViewModel(DataModel, this, propertyInfo) {Depth = depth};
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Events
|
||||||
|
|
||||||
|
public event EventHandler UpdateRequested;
|
||||||
|
|
||||||
|
protected virtual void OnUpdateRequested()
|
||||||
|
{
|
||||||
|
UpdateRequested?.Invoke(this, EventArgs.Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private void RequestUpdate()
|
||||||
|
{
|
||||||
|
Parent?.RequestUpdate();
|
||||||
|
OnUpdateRequested();
|
||||||
|
}
|
||||||
|
|
||||||
private void GetDescription()
|
private void GetDescription()
|
||||||
{
|
{
|
||||||
// If this is the first child of a root view model, use the data model description
|
// If this is the first child of a root view model, use the data model description
|
||||||
@ -218,7 +274,7 @@ namespace Artemis.UI.Shared.DataModelVisualization.Shared
|
|||||||
else if (PropertyInfo != null)
|
else if (PropertyInfo != null)
|
||||||
{
|
{
|
||||||
PropertyDescription = (DataModelPropertyAttribute) Attribute.GetCustomAttribute(PropertyInfo, typeof(DataModelPropertyAttribute)) ??
|
PropertyDescription = (DataModelPropertyAttribute) Attribute.GetCustomAttribute(PropertyInfo, typeof(DataModelPropertyAttribute)) ??
|
||||||
new DataModelPropertyAttribute {Name = PropertyInfo.Name.Humanize()};
|
new DataModelPropertyAttribute {Name = PropertyInfo.Name.Humanize(), ResetsDepth = false};
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
throw new ArtemisSharedUIException("Failed to get property description because plugin info is null but the parent has a datamodel");
|
throw new ArtemisSharedUIException("Failed to get property description because plugin info is null but the parent has a datamodel");
|
||||||
|
|||||||
@ -42,6 +42,7 @@ namespace Artemis.UI.Shared.Services
|
|||||||
|
|
||||||
// Update to populate children
|
// Update to populate children
|
||||||
viewModel.Update(this);
|
viewModel.Update(this);
|
||||||
|
viewModel.UpdateRequested += (sender, args) => viewModel.Update(this);
|
||||||
return viewModel;
|
return viewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,6 +57,7 @@ namespace Artemis.UI.Shared.Services
|
|||||||
|
|
||||||
// Update to populate children
|
// Update to populate children
|
||||||
viewModel.Update(this);
|
viewModel.Update(this);
|
||||||
|
viewModel.UpdateRequested += (sender, args) => viewModel.Update(this);
|
||||||
return viewModel;
|
return viewModel;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -185,6 +187,7 @@ namespace Artemis.UI.Shared.Services
|
|||||||
if (initialValue == null)
|
if (initialValue == null)
|
||||||
initialValue = Activator.CreateInstance(registration.SupportedType);
|
initialValue = Activator.CreateInstance(registration.SupportedType);
|
||||||
}
|
}
|
||||||
|
|
||||||
// This assumes the type can be converted, that has been checked when the VM was created
|
// This assumes the type can be converted, that has been checked when the VM was created
|
||||||
if (initialValue != null && initialValue.GetType() != registration.SupportedType)
|
if (initialValue != null && initialValue.GetType() != registration.SupportedType)
|
||||||
initialValue = Convert.ChangeType(initialValue, registration.SupportedType);
|
initialValue = Convert.ChangeType(initialValue, registration.SupportedType);
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Artemis.Core.Models.Profile;
|
using Artemis.Core.Models.Profile;
|
||||||
|
using Artemis.Core.Models.Profile.LayerProperties;
|
||||||
using Artemis.Core.Plugins.Abstract;
|
using Artemis.Core.Plugins.Abstract;
|
||||||
using Artemis.Core.Plugins.Models;
|
using Artemis.Core.Plugins.Models;
|
||||||
using Artemis.UI.Shared.Events;
|
using Artemis.UI.Shared.Events;
|
||||||
@ -76,11 +77,16 @@ namespace Artemis.UI.Shared.Services.Interfaces
|
|||||||
void RemovePropertyInput(PropertyInputRegistration registration);
|
void RemovePropertyInput(PropertyInputRegistration registration);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Snaps the given time to the closest relevant element in the timeline, this can be the cursor, a keyframe or a segment end.
|
/// Snaps the given time to the closest relevant element in the timeline, this can be the cursor, a keyframe or a
|
||||||
|
/// segment end.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="time"></param>
|
/// <param name="time"></param>
|
||||||
/// <param name="tolerance">How close the time must be to snap</param>
|
/// <param name="tolerance">How close the time must be to snap</param>
|
||||||
|
/// <param name="snapToSegments">Enable snapping to timeline segments</param>
|
||||||
|
/// <param name="snapToCurrentTime">Enable snapping to the current time of the editor</param>
|
||||||
|
/// <param name="snapToKeyframes">Enable snapping to visible keyframes</param>
|
||||||
|
/// <param name="excludedKeyframe">A keyframe to exclude during keyframe snapping</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
TimeSpan SnapToTimeline(TimeSpan time, TimeSpan tolerance, bool snapToSegments, bool snapToCurrentTime, bool snapToKeyframes);
|
TimeSpan SnapToTimeline(TimeSpan time, TimeSpan tolerance, bool snapToSegments, bool snapToCurrentTime, bool snapToKeyframes, BaseLayerPropertyKeyframe excludedKeyframe = null);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -113,20 +113,11 @@ namespace Artemis.UI.Shared.Services
|
|||||||
if (SelectedProfile == null)
|
if (SelectedProfile == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var delta = CurrentTime - _lastUpdateTime;
|
// Stick to the main segment for any element that is not currently selected
|
||||||
foreach (var folder in SelectedProfile.GetAllFolders())
|
foreach (var folder in SelectedProfile.GetAllFolders())
|
||||||
{
|
folder.OverrideProgress(CurrentTime, folder != SelectedProfileElement);
|
||||||
foreach (var baseLayerEffect in folder.LayerEffects)
|
|
||||||
baseLayerEffect.Update(delta.TotalSeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
foreach (var layer in SelectedProfile.GetAllLayers())
|
foreach (var layer in SelectedProfile.GetAllLayers())
|
||||||
{
|
layer.OverrideProgress(CurrentTime, layer != SelectedProfileElement);
|
||||||
layer.OverrideProgress(CurrentTime);
|
|
||||||
layer.LayerBrush?.Update(delta.TotalSeconds);
|
|
||||||
foreach (var baseLayerEffect in layer.LayerEffects)
|
|
||||||
baseLayerEffect.Update(delta.TotalSeconds);
|
|
||||||
}
|
|
||||||
|
|
||||||
_lastUpdateTime = CurrentTime;
|
_lastUpdateTime = CurrentTime;
|
||||||
OnProfilePreviewUpdated();
|
OnProfilePreviewUpdated();
|
||||||
@ -205,7 +196,7 @@ namespace Artemis.UI.Shared.Services
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public TimeSpan SnapToTimeline(TimeSpan time, TimeSpan tolerance, bool snapToSegments, bool snapToCurrentTime, bool snapToKeyframes)
|
public TimeSpan SnapToTimeline(TimeSpan time, TimeSpan tolerance, bool snapToSegments, bool snapToCurrentTime, bool snapToKeyframes, BaseLayerPropertyKeyframe excludedKeyframe = null)
|
||||||
{
|
{
|
||||||
if (snapToSegments)
|
if (snapToSegments)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -12,10 +12,12 @@ namespace Artemis.UI.Converters
|
|||||||
public object Convert(object value, Type targetType, object parameter,
|
public object Convert(object value, Type targetType, object parameter,
|
||||||
CultureInfo culture)
|
CultureInfo culture)
|
||||||
{
|
{
|
||||||
if (targetType != typeof(bool))
|
if (targetType == typeof(bool))
|
||||||
throw new InvalidOperationException("The target must be a boolean");
|
return !(bool) value;
|
||||||
|
if (targetType == typeof(bool?))
|
||||||
|
return !(bool?) value;
|
||||||
|
|
||||||
return !(bool) value;
|
throw new InvalidOperationException("The target must be a boolean");
|
||||||
}
|
}
|
||||||
|
|
||||||
public object ConvertBack(object value, Type targetType, object parameter,
|
public object ConvertBack(object value, Type targetType, object parameter,
|
||||||
|
|||||||
@ -10,9 +10,33 @@
|
|||||||
d:DesignHeight="450" d:DesignWidth="800"
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
d:DataContext="{d:DesignInstance Type=local:DisplayConditionGroupViewModel, IsDesignTimeCreatable=False}">
|
d:DataContext="{d:DesignInstance Type=local:DisplayConditionGroupViewModel, IsDesignTimeCreatable=False}">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<ResourceDictionary Source="pack://application:,,,/Artemis.UI;component/ResourceDictionaries/DisplayConditions.xaml" />
|
<ResourceDictionary>
|
||||||
|
<ResourceDictionary.MergedDictionaries>
|
||||||
|
<ResourceDictionary Source="pack://application:,,,/Artemis.UI;component/ResourceDictionaries/DisplayConditions.xaml" />
|
||||||
|
<ResourceDictionary>
|
||||||
|
<Style TargetType="Grid" x:Key="InitializingFade">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding IsInitialized}" Value="True">
|
||||||
|
<DataTrigger.EnterActions>
|
||||||
|
<BeginStoryboard>
|
||||||
|
<Storyboard>
|
||||||
|
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0.0" To="1.0" Duration="0:0:0.25" BeginTime="0:0:0.1">
|
||||||
|
<DoubleAnimation.EasingFunction>
|
||||||
|
<QuadraticEase EasingMode="EaseInOut" />
|
||||||
|
</DoubleAnimation.EasingFunction>
|
||||||
|
</DoubleAnimation>
|
||||||
|
</Storyboard>
|
||||||
|
</BeginStoryboard>
|
||||||
|
</DataTrigger.EnterActions>
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</ResourceDictionary>
|
||||||
|
</ResourceDictionary.MergedDictionaries>
|
||||||
|
</ResourceDictionary>
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid>
|
|
||||||
|
<Grid Style="{StaticResource InitializingFade}" Opacity="0">
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
|
|||||||
@ -1,9 +1,11 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
|
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 Humanizer;
|
using Humanizer;
|
||||||
|
using Stylet;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
||||||
{
|
{
|
||||||
@ -11,11 +13,17 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
{
|
{
|
||||||
private readonly IDisplayConditionsVmFactory _displayConditionsVmFactory;
|
private readonly IDisplayConditionsVmFactory _displayConditionsVmFactory;
|
||||||
private bool _isRootGroup;
|
private bool _isRootGroup;
|
||||||
|
private bool _isInitialized;
|
||||||
|
|
||||||
public DisplayConditionGroupViewModel(DisplayConditionGroup displayConditionGroup, DisplayConditionViewModel parent, IDisplayConditionsVmFactory displayConditionsVmFactory) : base(
|
public DisplayConditionGroupViewModel(DisplayConditionGroup displayConditionGroup, DisplayConditionViewModel parent, IDisplayConditionsVmFactory displayConditionsVmFactory) : base(
|
||||||
displayConditionGroup, parent)
|
displayConditionGroup, parent)
|
||||||
{
|
{
|
||||||
_displayConditionsVmFactory = displayConditionsVmFactory;
|
_displayConditionsVmFactory = displayConditionsVmFactory;
|
||||||
|
Execute.PostToUIThread(async () =>
|
||||||
|
{
|
||||||
|
await Task.Delay(50);
|
||||||
|
IsInitialized = true;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public DisplayConditionGroup DisplayConditionGroup => (DisplayConditionGroup) Model;
|
public DisplayConditionGroup DisplayConditionGroup => (DisplayConditionGroup) Model;
|
||||||
@ -26,6 +34,12 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
set => SetAndNotify(ref _isRootGroup, value);
|
set => SetAndNotify(ref _isRootGroup, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public bool IsInitialized
|
||||||
|
{
|
||||||
|
get => _isInitialized;
|
||||||
|
set => SetAndNotify(ref _isInitialized, value);
|
||||||
|
}
|
||||||
|
|
||||||
public string SelectedBooleanOperator => DisplayConditionGroup.BooleanOperator.Humanize();
|
public string SelectedBooleanOperator => DisplayConditionGroup.BooleanOperator.Humanize();
|
||||||
|
|
||||||
public void SelectBooleanOperator(string type)
|
public void SelectBooleanOperator(string type)
|
||||||
|
|||||||
@ -20,11 +20,28 @@
|
|||||||
<ResourceDictionary>
|
<ResourceDictionary>
|
||||||
<converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
<converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||||
<utilities:BindingProxy x:Key="DataContextProxy" Data="{Binding}" />
|
<utilities:BindingProxy x:Key="DataContextProxy" Data="{Binding}" />
|
||||||
|
<Style TargetType="Grid" x:Key="InitializingFade">
|
||||||
|
<Style.Triggers>
|
||||||
|
<DataTrigger Binding="{Binding IsInitialized}" Value="True">
|
||||||
|
<DataTrigger.EnterActions>
|
||||||
|
<BeginStoryboard>
|
||||||
|
<Storyboard>
|
||||||
|
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0.0" To="1.0" Duration="0:0:0.25" BeginTime="0:0:0.1">
|
||||||
|
<DoubleAnimation.EasingFunction>
|
||||||
|
<QuadraticEase EasingMode="EaseInOut" />
|
||||||
|
</DoubleAnimation.EasingFunction>
|
||||||
|
</DoubleAnimation>
|
||||||
|
</Storyboard>
|
||||||
|
</BeginStoryboard>
|
||||||
|
</DataTrigger.EnterActions>
|
||||||
|
</DataTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</ResourceDictionary.MergedDictionaries>
|
</ResourceDictionary.MergedDictionaries>
|
||||||
</ResourceDictionary>
|
</ResourceDictionary>
|
||||||
</UserControl.Resources>
|
</UserControl.Resources>
|
||||||
<Grid Margin="0 3">
|
<Grid Margin="0 3" Style="{StaticResource InitializingFade}" Opacity="0">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
@ -61,6 +78,7 @@
|
|||||||
<Setter Property="CommandParameter" Value="{Binding}" />
|
<Setter Property="CommandParameter" Value="{Binding}" />
|
||||||
<Setter Property="CommandTarget" Value="{Binding}" />
|
<Setter Property="CommandTarget" Value="{Binding}" />
|
||||||
<Setter Property="IsEnabled" Value="{Binding IsMatchingFilteredTypes}" />
|
<Setter Property="IsEnabled" Value="{Binding IsMatchingFilteredTypes}" />
|
||||||
|
<Setter Property="IsSubmenuOpen" Value="{Binding IsVisualizationExpanded, Mode=TwoWay}" />
|
||||||
</Style>
|
</Style>
|
||||||
</ContextMenu.ItemContainerStyle>
|
</ContextMenu.ItemContainerStyle>
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
|
|||||||
@ -28,12 +28,13 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
private DataModelPropertiesViewModel _rightSideDataModel;
|
private DataModelPropertiesViewModel _rightSideDataModel;
|
||||||
private DataModelInputViewModel _rightSideInputViewModel;
|
private DataModelInputViewModel _rightSideInputViewModel;
|
||||||
private int _rightSideTransitionIndex;
|
private int _rightSideTransitionIndex;
|
||||||
|
private object _rightStaticValue;
|
||||||
private DataModelVisualizationViewModel _selectedLeftSideProperty;
|
private DataModelVisualizationViewModel _selectedLeftSideProperty;
|
||||||
private DisplayConditionOperator _selectedOperator;
|
private DisplayConditionOperator _selectedOperator;
|
||||||
private DataModelVisualizationViewModel _selectedRightSideProperty;
|
private DataModelVisualizationViewModel _selectedRightSideProperty;
|
||||||
|
|
||||||
private List<Type> _supportedInputTypes;
|
private List<Type> _supportedInputTypes;
|
||||||
private object _rightStaticValue;
|
private bool _isInitialized;
|
||||||
|
|
||||||
public DisplayConditionPredicateViewModel(DisplayConditionPredicate displayConditionPredicate, DisplayConditionViewModel parent, IProfileEditorService profileEditorService,
|
public DisplayConditionPredicateViewModel(DisplayConditionPredicate displayConditionPredicate, DisplayConditionViewModel parent, IProfileEditorService profileEditorService,
|
||||||
IDataModelVisualizationService dataModelVisualizationService, IDataModelService dataModelService, IEventAggregator eventAggregator)
|
IDataModelVisualizationService dataModelVisualizationService, IDataModelService dataModelService, IEventAggregator eventAggregator)
|
||||||
@ -56,7 +57,11 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
public bool ShowRightSidePropertySelection => DisplayConditionPredicate.PredicateType == PredicateType.Dynamic;
|
public bool ShowRightSidePropertySelection => DisplayConditionPredicate.PredicateType == PredicateType.Dynamic;
|
||||||
public bool CanActivateRightSideInputViewModel => SelectedLeftSideProperty?.PropertyInfo != null;
|
public bool CanActivateRightSideInputViewModel => SelectedLeftSideProperty?.PropertyInfo != null;
|
||||||
|
|
||||||
public bool IsInitialized { get; private set; }
|
public bool IsInitialized
|
||||||
|
{
|
||||||
|
get => _isInitialized;
|
||||||
|
private set => SetAndNotify(ref _isInitialized, value);
|
||||||
|
}
|
||||||
|
|
||||||
public DataModelPropertiesViewModel LeftSideDataModel
|
public DataModelPropertiesViewModel LeftSideDataModel
|
||||||
{
|
{
|
||||||
@ -156,6 +161,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
_supportedInputTypes = editors.Select(e => e.SupportedType).ToList();
|
_supportedInputTypes = editors.Select(e => e.SupportedType).ToList();
|
||||||
_supportedInputTypes.AddRange(editors.Where(e => e.CompatibleConversionTypes != null).SelectMany(e => e.CompatibleConversionTypes));
|
_supportedInputTypes.AddRange(editors.Where(e => e.CompatibleConversionTypes != null).SelectMany(e => e.CompatibleConversionTypes));
|
||||||
|
|
||||||
|
|
||||||
|
LeftSideDataModel.UpdateRequested += LeftDataModelUpdateRequested;
|
||||||
|
RightSideDataModel.UpdateRequested += RightDataModelUpdateRequested;
|
||||||
|
|
||||||
IsInitialized = true;
|
IsInitialized = true;
|
||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
@ -192,6 +201,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
public void ApplyLeftSide()
|
public void ApplyLeftSide()
|
||||||
{
|
{
|
||||||
DisplayConditionPredicate.UpdateLeftSide(SelectedLeftSideProperty.DataModel, SelectedLeftSideProperty.PropertyPath);
|
DisplayConditionPredicate.UpdateLeftSide(SelectedLeftSideProperty.DataModel, SelectedLeftSideProperty.PropertyPath);
|
||||||
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
|
|
||||||
SelectedOperator = DisplayConditionPredicate.Operator;
|
SelectedOperator = DisplayConditionPredicate.Operator;
|
||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
@ -199,6 +210,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
public void ApplyRightSideDynamic()
|
public void ApplyRightSideDynamic()
|
||||||
{
|
{
|
||||||
DisplayConditionPredicate.UpdateRightSide(SelectedRightSideProperty.DataModel, SelectedRightSideProperty.PropertyPath);
|
DisplayConditionPredicate.UpdateRightSide(SelectedRightSideProperty.DataModel, SelectedRightSideProperty.PropertyPath);
|
||||||
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
|
|
||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -207,6 +220,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
if (isSubmitted)
|
if (isSubmitted)
|
||||||
{
|
{
|
||||||
DisplayConditionPredicate.UpdateRightSide(value);
|
DisplayConditionPredicate.UpdateRightSide(value);
|
||||||
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
|
|
||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -219,6 +234,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
public void ApplyOperator()
|
public void ApplyOperator()
|
||||||
{
|
{
|
||||||
DisplayConditionPredicate.UpdateOperator(SelectedOperator);
|
DisplayConditionPredicate.UpdateOperator(SelectedOperator);
|
||||||
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
|
|
||||||
Update();
|
Update();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,6 +254,18 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
_eventAggregator.Subscribe(this);
|
_eventAggregator.Subscribe(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void RightDataModelUpdateRequested(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (DisplayConditionPredicate.PredicateType == PredicateType.Dynamic)
|
||||||
|
SelectedRightSideProperty = LeftSideDataModel.GetChildForCondition(DisplayConditionPredicate, DisplayConditionSide.Right);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void LeftDataModelUpdateRequested(object sender, EventArgs e)
|
||||||
|
{
|
||||||
|
if (DisplayConditionPredicate.PredicateType == PredicateType.Static)
|
||||||
|
LeftSideDataModel.ApplyTypeFilter(false, _supportedInputTypes.ToArray());
|
||||||
|
}
|
||||||
|
|
||||||
private void ExecuteSelectLeftProperty(object context)
|
private void ExecuteSelectLeftProperty(object context)
|
||||||
{
|
{
|
||||||
if (!(context is DataModelVisualizationViewModel dataModelVisualizationViewModel))
|
if (!(context is DataModelVisualizationViewModel dataModelVisualizationViewModel))
|
||||||
|
|||||||
@ -1,73 +1,71 @@
|
|||||||
<UserControl
|
<UserControl
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions"
|
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:s="https://github.com/canton7/Stylet"
|
xmlns:s="https://github.com/canton7/Stylet"
|
||||||
xmlns:Converters="clr-namespace:Artemis.UI.Converters" x:Class="Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions.DisplayConditionsView"
|
x:Class="Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions.DisplayConditionsView"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800"
|
d:DesignHeight="450" d:DesignWidth="800"
|
||||||
d:DataContext="{d:DesignInstance {x:Type local:DisplayConditionsViewModel}}">
|
d:DataContext="{d:DesignInstance {x:Type local:DisplayConditionsViewModel}}">
|
||||||
<UserControl.Resources>
|
|
||||||
<Converters:InverseBooleanConverter x:Key="InverseBooleanConverter"/>
|
|
||||||
</UserControl.Resources>
|
|
||||||
<Grid>
|
<Grid>
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto" />
|
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Grid.RowDefinitions>
|
<Grid.RowDefinitions>
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<TextBlock Grid.ColumnSpan="2" Style="{StaticResource MaterialDesignSubtitle1TextBlock}" Margin="10 5 0 -4"><Run Text="Display conditions"/></TextBlock>
|
<TextBlock Style="{StaticResource MaterialDesignSubtitle1TextBlock}" Margin="10 5 0 -4">
|
||||||
<Separator Grid.Row="1" Grid.Column="0" Grid.ColumnSpan="2" Style="{StaticResource MaterialDesignDarkSeparator}" Margin="8 0" />
|
Display conditions
|
||||||
|
</TextBlock>
|
||||||
|
<Separator Grid.Row="1" Grid.Column="0" Style="{StaticResource MaterialDesignDarkSeparator}" Margin="8 0" />
|
||||||
|
|
||||||
<Grid Grid.Row="2" Grid.Column="0" Grid.ColumnSpan="2">
|
<Grid Grid.Row="2" Grid.Column="0">
|
||||||
<ScrollViewer Margin="8 0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
<ScrollViewer Margin="8 0" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
|
||||||
<ContentControl s:View.Model="{Binding RootGroup}" />
|
<ContentControl s:View.Model="{Binding RootGroup}" />
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
<StackPanel Grid.Row="3" Grid.Column="0" Margin="13" Orientation="Horizontal" VerticalAlignment="Bottom" ToolTip="When conditions are met, only go through the entire timeline once.">
|
<StackPanel Grid.Row="3" Margin="10" HorizontalAlignment="Right" Orientation="Horizontal">
|
||||||
<CheckBox Style="{StaticResource MaterialDesignCheckBox}" Content="Play once" IsChecked="{Binding RenderProfileElement.RepeatMainSegment, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}"/>
|
<TextBlock VerticalAlignment="Center" Margin="0 0 10 0">When conditions no longer met</TextBlock>
|
||||||
</StackPanel>
|
<ListBox Style="{StaticResource MaterialDesignToolToggleListBox}" SelectedIndex="{Binding ConditionBehaviourIndex}" IsEnabled="{Binding ConditionBehaviourEnabled}" Height="22">
|
||||||
|
|
||||||
<StackPanel Grid.Row="3" Grid.Column="1" Margin="10" HorizontalAlignment="Right">
|
|
||||||
<TextBlock><Run Text="When conditions no longer met"/></TextBlock>
|
|
||||||
<ListBox Style="{StaticResource MaterialDesignToolToggleListBox}" SelectedIndex="{Binding CurrentTimelineIndex}" Height="20" Margin="0 5 0 0">
|
|
||||||
<ListBoxItem Padding="10 0">
|
<ListBoxItem Padding="10 0">
|
||||||
<ListBoxItem.ToolTip>
|
<ListBoxItem.ToolTip>
|
||||||
<ToolTip Placement="Top" VerticalOffset="-5">
|
<ToolTip Placement="Top" VerticalOffset="-5">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBlock><Run Text="When conditions are no longer met, finish the timelines and then stop displaying."/></TextBlock>
|
<TextBlock>
|
||||||
|
When conditions are no longer met, finish the timelines and then stop displaying.
|
||||||
|
</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ToolTip>
|
</ToolTip>
|
||||||
</ListBoxItem.ToolTip>
|
</ListBoxItem.ToolTip>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<materialDesign:PackIcon Kind="PlayArrow" Width="20" Height="20" Margin="0 -4" />
|
<materialDesign:PackIcon Kind="PlayArrow" Width="20" Height="20" Margin="0 -4" />
|
||||||
<TextBlock Margin="5 0 0 0" FontSize="11"><Run Text="WAIT FOR FINISH"/></TextBlock>
|
<TextBlock Margin="5 0 0 0" FontSize="11">
|
||||||
|
WAIT FOR FINISH
|
||||||
|
</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ListBoxItem>
|
</ListBoxItem>
|
||||||
<ListBoxItem Padding="10 0">
|
<ListBoxItem Padding="10 0">
|
||||||
<ListBoxItem.ToolTip>
|
<ListBoxItem.ToolTip>
|
||||||
<ToolTip Placement="Top" VerticalOffset="-5">
|
<ToolTip Placement="Top" VerticalOffset="-5">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<TextBlock><Run Text="When conditions are no longer met, stop displaying immediately."/></TextBlock>
|
<TextBlock>
|
||||||
|
When conditions are no longer met, stop displaying immediately.
|
||||||
|
</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ToolTip>
|
</ToolTip>
|
||||||
</ListBoxItem.ToolTip>
|
</ListBoxItem.ToolTip>
|
||||||
<StackPanel Orientation="Horizontal">
|
<StackPanel Orientation="Horizontal">
|
||||||
<materialDesign:PackIcon Kind="SkipNext" Width="20" Height="20" Margin="0 -4" />
|
<materialDesign:PackIcon Kind="SkipNext" Width="20" Height="20" Margin="0 -4" />
|
||||||
<TextBlock Margin="5 0 0 0" FontSize="11"><Run Text="SKIP"/></TextBlock>
|
<TextBlock Margin="5 0 0 0" FontSize="11">
|
||||||
|
SKIP
|
||||||
|
</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ListBoxItem>
|
</ListBoxItem>
|
||||||
</ListBox>
|
</ListBox>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
</Grid>
|
</Grid>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -9,12 +9,14 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
{
|
{
|
||||||
public class DisplayConditionsViewModel : ProfileEditorPanelViewModel
|
public class DisplayConditionsViewModel : ProfileEditorPanelViewModel
|
||||||
{
|
{
|
||||||
|
private readonly IProfileEditorService _profileEditorService;
|
||||||
private readonly IDisplayConditionsVmFactory _displayConditionsVmFactory;
|
private readonly IDisplayConditionsVmFactory _displayConditionsVmFactory;
|
||||||
private DisplayConditionGroupViewModel _rootGroup;
|
private DisplayConditionGroupViewModel _rootGroup;
|
||||||
private RenderProfileElement _renderProfileElement;
|
private RenderProfileElement _renderProfileElement;
|
||||||
|
|
||||||
public DisplayConditionsViewModel(IProfileEditorService profileEditorService, IDisplayConditionsVmFactory displayConditionsVmFactory)
|
public DisplayConditionsViewModel(IProfileEditorService profileEditorService, IDisplayConditionsVmFactory displayConditionsVmFactory)
|
||||||
{
|
{
|
||||||
|
_profileEditorService = profileEditorService;
|
||||||
_displayConditionsVmFactory = displayConditionsVmFactory;
|
_displayConditionsVmFactory = displayConditionsVmFactory;
|
||||||
profileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected;
|
profileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected;
|
||||||
}
|
}
|
||||||
@ -31,9 +33,28 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.DisplayConditions
|
|||||||
set => SetAndNotify(ref _renderProfileElement, value);
|
set => SetAndNotify(ref _renderProfileElement, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int ConditionBehaviourIndex
|
||||||
|
{
|
||||||
|
get => RenderProfileElement != null && RenderProfileElement.AlwaysFinishTimeline ? 0 : 1;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
if (RenderProfileElement == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RenderProfileElement.AlwaysFinishTimeline = value == 0;
|
||||||
|
NotifyOfPropertyChange(nameof(ConditionBehaviourIndex));
|
||||||
|
|
||||||
|
_profileEditorService.UpdateSelectedProfileElement();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool ConditionBehaviourEnabled => RenderProfileElement != null;
|
||||||
|
|
||||||
private void ProfileEditorServiceOnProfileElementSelected(object sender, RenderProfileElementEventArgs e)
|
private void ProfileEditorServiceOnProfileElementSelected(object sender, RenderProfileElementEventArgs e)
|
||||||
{
|
{
|
||||||
RenderProfileElement = e.RenderProfileElement;
|
RenderProfileElement = e.RenderProfileElement;
|
||||||
|
NotifyOfPropertyChange(nameof(ConditionBehaviourIndex));
|
||||||
|
NotifyOfPropertyChange(nameof(ConditionBehaviourEnabled));
|
||||||
|
|
||||||
if (e.RenderProfileElement == null)
|
if (e.RenderProfileElement == null)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -8,7 +8,9 @@
|
|||||||
xmlns:timeline="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline"
|
xmlns:timeline="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline"
|
||||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||||
xmlns:behaviors="clr-namespace:Artemis.UI.Behaviors"
|
xmlns:behaviors="clr-namespace:Artemis.UI.Behaviors"
|
||||||
xmlns:Converters="clr-namespace:Artemis.UI.Converters" x:Class="Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.LayerPropertiesView"
|
xmlns:Converters="clr-namespace:Artemis.UI.Converters"
|
||||||
|
xmlns:utilities="clr-namespace:Artemis.UI.Utilities"
|
||||||
|
x:Class="Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.LayerPropertiesView"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450"
|
d:DesignHeight="450"
|
||||||
d:DesignWidth="800"
|
d:DesignWidth="800"
|
||||||
@ -16,6 +18,7 @@
|
|||||||
behaviors:InputBindingBehavior.PropagateInputBindingsToWindow="True">
|
behaviors:InputBindingBehavior.PropagateInputBindingsToWindow="True">
|
||||||
<UserControl.Resources>
|
<UserControl.Resources>
|
||||||
<Converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
<Converters:NullToVisibilityConverter x:Key="NullToVisibilityConverter" />
|
||||||
|
<utilities:BindingProxy x:Key="DataContextProxy" Data="{Binding}" />
|
||||||
<Style x:Key="SvStyle" TargetType="{x:Type ScrollViewer}">
|
<Style x:Key="SvStyle" TargetType="{x:Type ScrollViewer}">
|
||||||
<Setter Property="OverridesDefaultStyle" Value="True" />
|
<Setter Property="OverridesDefaultStyle" Value="True" />
|
||||||
<Setter Property="Template">
|
<Setter Property="Template">
|
||||||
@ -199,58 +202,78 @@
|
|||||||
Width="{Binding ActualWidth, ElementName=PropertyTimeLine}" />
|
Width="{Binding ActualWidth, ElementName=PropertyTimeLine}" />
|
||||||
|
|
||||||
<!-- Start segment -->
|
<!-- Start segment -->
|
||||||
<TextBlock Grid.Column="0"
|
<Grid Grid.Column="0" VerticalAlignment="Top" Background="{StaticResource MaterialDesignPaper}"
|
||||||
TextAlignment="Center"
|
Visibility="{Binding StartSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
|
||||||
VerticalAlignment="Top"
|
<Grid.ColumnDefinitions>
|
||||||
Padding="0 3"
|
<ColumnDefinition Width="*" />
|
||||||
FontSize="11"
|
<ColumnDefinition Width="Auto" />
|
||||||
Background="{StaticResource MaterialDesignPaper}"
|
</Grid.ColumnDefinitions>
|
||||||
Visibility="{Binding StartSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"
|
<TextBlock TextAlignment="Center" Padding="0 3" FontSize="12" ToolTip="This segment is played when a layer starts displaying because it's conditions are met">
|
||||||
ToolTip="This segment is played when a layer starts displaying because it's conditions are met">
|
Start
|
||||||
Start
|
</TextBlock>
|
||||||
</TextBlock>
|
<Button Grid.Column="1" Style="{StaticResource MaterialDesignIconButton}" ToolTip="Disable start segment" Width="20" Height="20" Margin="0 0 6 0"
|
||||||
|
Command="{s:Action DisableSegment}" CommandParameter="Start">
|
||||||
|
<materialDesign:PackIcon Kind="Close" Height="18" Width="18" />
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<!-- Main segment -->
|
<!-- Main segment -->
|
||||||
<TextBlock Grid.Column="1"
|
<Grid Grid.Column="1" VerticalAlignment="Top" Background="{StaticResource MaterialDesignPaper}"
|
||||||
TextAlignment="Center"
|
Visibility="{Binding MainSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
|
||||||
VerticalAlignment="Top"
|
<Grid.ColumnDefinitions>
|
||||||
Padding="0 3"
|
<ColumnDefinition Width="*" />
|
||||||
FontSize="11"
|
<ColumnDefinition Width="Auto" />
|
||||||
Background="{StaticResource MaterialDesignPaper}"
|
<ColumnDefinition Width="Auto" />
|
||||||
ToolTip="This segment is played while a condition is met, either once or on a repeating loop">
|
</Grid.ColumnDefinitions>
|
||||||
Main
|
<TextBlock TextAlignment="Center" Padding="0 3" FontSize="12" ToolTip="This segment is played while a condition is met, either once or on a repeating loop">
|
||||||
</TextBlock>
|
Main
|
||||||
|
</TextBlock>
|
||||||
|
|
||||||
|
<ToggleButton Grid.Column="1" Style="{StaticResource MaterialDesignFlatToggleButton}" ToolTip="Toggle main segment repeat" Width="16" Height="16"
|
||||||
|
IsChecked="{Binding RepeatMainSegment}" VerticalAlignment="Center">
|
||||||
|
<materialDesign:PackIcon Kind="Repeat" Height="12" Width="12" />
|
||||||
|
</ToggleButton>
|
||||||
|
|
||||||
|
<Button Grid.Column="2" Style="{StaticResource MaterialDesignIconButton}" ToolTip="Remove" Width="20" Height="20" Margin="5 0 8 0"
|
||||||
|
Command="{s:Action DisableSegment}" CommandParameter="Main">
|
||||||
|
<materialDesign:PackIcon Kind="Close" Height="18" Width="18" />
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<!-- End segment -->
|
<!-- End segment -->
|
||||||
<TextBlock Grid.Column="2"
|
<Grid Grid.Column="2" VerticalAlignment="Top" Background="{StaticResource MaterialDesignPaper}"
|
||||||
TextAlignment="Center"
|
Visibility="{Binding EndSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
|
||||||
VerticalAlignment="Top"
|
<Grid.ColumnDefinitions>
|
||||||
Padding="0 3"
|
<ColumnDefinition Width="*" />
|
||||||
FontSize="11"
|
<ColumnDefinition Width="Auto" />
|
||||||
Background="{StaticResource MaterialDesignPaper}"
|
</Grid.ColumnDefinitions>
|
||||||
Visibility="{Binding EndSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"
|
<TextBlock TextAlignment="Center" Padding="0 3" FontSize="12" ToolTip="This segment is played once a condition is no longer met">
|
||||||
ToolTip="This segment is played once a condition is no longer met">
|
End
|
||||||
End
|
</TextBlock>
|
||||||
</TextBlock>
|
<Button Grid.Column="1" Style="{StaticResource MaterialDesignIconButton}" ToolTip="Disable end segment" Width="20" Height="20" Margin="0 0 6 0"
|
||||||
|
Command="{s:Action DisableSegment}" CommandParameter="End">
|
||||||
|
<materialDesign:PackIcon Kind="Close" Height="18" Width="18" />
|
||||||
|
</Button>
|
||||||
|
</Grid>
|
||||||
|
|
||||||
<!-- Segment movement display -->
|
<!-- Segment movement display -->
|
||||||
<Rectangle Grid.Column="0" RadiusX="2" RadiusY="2" Fill="{DynamicResource PrimaryHueDarkBrush}" Margin="0 -1 -2 0" Width="5" Height="20" VerticalAlignment="Top"
|
<Rectangle Grid.Column="0" RadiusX="2" RadiusY="2" Fill="{DynamicResource PrimaryHueDarkBrush}" Margin="0 -2 -2 0" Width="5" Height="24" VerticalAlignment="Top"
|
||||||
HorizontalAlignment="Right" Visibility="{Binding StartSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}" />
|
HorizontalAlignment="Right" Visibility="{Binding StartSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}" />
|
||||||
<Rectangle Grid.Column="1" RadiusX="2" RadiusY="2" Fill="{DynamicResource PrimaryHueDarkBrush}" Margin="0 -1 -2 0" Width="5" Height="20" VerticalAlignment="Top"
|
<Rectangle Grid.Column="1" RadiusX="2" RadiusY="2" Fill="{DynamicResource PrimaryHueDarkBrush}" Margin="0 -2 -2 0" Width="5" Height="24" VerticalAlignment="Top"
|
||||||
HorizontalAlignment="Right" />
|
HorizontalAlignment="Right" Visibility="{Binding MainSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}" />
|
||||||
<Rectangle Grid.Column="2" RadiusX="2" RadiusY="2" Fill="{DynamicResource PrimaryHueDarkBrush}" Margin="0 -1 -2 0" Width="5" Height="20" VerticalAlignment="Top"
|
<Rectangle Grid.Column="2" RadiusX="2" RadiusY="2" Fill="{DynamicResource PrimaryHueDarkBrush}" Margin="0 -2 -2 0" Width="5" Height="24" VerticalAlignment="Top"
|
||||||
HorizontalAlignment="Right" Visibility="{Binding EndSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}" />
|
HorizontalAlignment="Right" Visibility="{Binding EndSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}" />
|
||||||
|
|
||||||
<!-- Segment movement handles -->
|
<!-- Segment movement handles -->
|
||||||
<Rectangle Grid.Column="0" RadiusX="2" RadiusY="2" Fill="Transparent" Margin="0 -1 -6 0" Width="16" Height="20" VerticalAlignment="Top"
|
<Rectangle Grid.Column="0" RadiusX="2" RadiusY="2" Fill="Transparent" Margin="0 -1 -6 0" Width="16" Height="25" VerticalAlignment="Top"
|
||||||
HorizontalAlignment="Right" Cursor="SizeWE" Visibility="{Binding StartSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"
|
HorizontalAlignment="Right" Cursor="SizeWE" Visibility="{Binding StartSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"
|
||||||
MouseDown="{s:Action StartSegmentMouseDown}" MouseUp="{s:Action StartSegmentMouseUp}" MouseMove="{s:Action SegmentMouseMove}"/>
|
MouseDown="{s:Action StartSegmentMouseDown}" MouseUp="{s:Action StartSegmentMouseUp}" MouseMove="{s:Action SegmentMouseMove}" />
|
||||||
<Rectangle Grid.Column="1" RadiusX="2" RadiusY="2" Fill="Transparent" Margin="0 -1 -6 0" Width="16" Height="20" VerticalAlignment="Top"
|
<Rectangle Grid.Column="1" RadiusX="2" RadiusY="2" Fill="Transparent" Margin="0 -1 -6 0" Width="16" Height="25" VerticalAlignment="Top"
|
||||||
HorizontalAlignment="Right" Cursor="SizeWE"
|
HorizontalAlignment="Right" Cursor="SizeWE" Visibility="{Binding MainSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"
|
||||||
MouseDown="{s:Action MainSegmentMouseDown}" MouseUp="{s:Action MainSegmentMouseUp}" MouseMove="{s:Action SegmentMouseMove}"/>
|
MouseDown="{s:Action MainSegmentMouseDown}" MouseUp="{s:Action MainSegmentMouseUp}" MouseMove="{s:Action SegmentMouseMove}" />
|
||||||
<Rectangle Grid.Column="2" RadiusX="2" RadiusY="2" Fill="Transparent" Margin="0 -1 -6 0" Width="16" Height="20" VerticalAlignment="Top"
|
<Rectangle Grid.Column="2" RadiusX="2" RadiusY="2" Fill="Transparent" Margin="0 -1 -6 0" Width="16" Height="25" VerticalAlignment="Top"
|
||||||
HorizontalAlignment="Right" Cursor="SizeWE" Visibility="{Binding EndSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"
|
HorizontalAlignment="Right" Cursor="SizeWE" Visibility="{Binding EndSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"
|
||||||
MouseDown="{s:Action EndSegmentMouseDown}" MouseUp="{s:Action EndSegmentMouseUp}" MouseMove="{s:Action SegmentMouseMove}"/>
|
MouseDown="{s:Action EndSegmentMouseDown}" MouseUp="{s:Action EndSegmentMouseUp}" MouseMove="{s:Action SegmentMouseMove}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|
||||||
@ -348,19 +371,59 @@
|
|||||||
Background="{DynamicResource MaterialDesignCardBackground}">
|
Background="{DynamicResource MaterialDesignCardBackground}">
|
||||||
|
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="*" />
|
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
|
<ColumnDefinition Width="*" />
|
||||||
</Grid.ColumnDefinitions>
|
</Grid.ColumnDefinitions>
|
||||||
|
|
||||||
<StackPanel Grid.Column="0" Orientation="Horizontal">
|
<Button Grid.Column="0"
|
||||||
<CheckBox Style="{StaticResource MaterialDesignCheckBox}" IsChecked="{Binding StartSegmentEnabled}">
|
Margin="5 -2 0 -2"
|
||||||
Enable start segment
|
Padding="10 0"
|
||||||
</CheckBox>
|
Height="20"
|
||||||
|
Width="110"
|
||||||
<CheckBox Style="{StaticResource MaterialDesignCheckBox}" Margin="10 0" IsChecked="{Binding EndSegmentEnabled}">
|
ToolTip="Select an effect to add"
|
||||||
Enable end segment
|
VerticalAlignment="Center"
|
||||||
</CheckBox>
|
Visibility="{Binding PropertyTreeVisible, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"
|
||||||
</StackPanel>
|
IsEnabled="{Binding CanAddSegment}">
|
||||||
|
<Button.Style>
|
||||||
|
<Style TargetType="{x:Type Button}" BasedOn="{StaticResource MaterialDesignFlatMidBgButton}">
|
||||||
|
<Style.Triggers>
|
||||||
|
<EventTrigger RoutedEvent="Click">
|
||||||
|
<EventTrigger.Actions>
|
||||||
|
<BeginStoryboard>
|
||||||
|
<Storyboard>
|
||||||
|
<BooleanAnimationUsingKeyFrames Storyboard.TargetProperty="ContextMenu.IsOpen">
|
||||||
|
<DiscreteBooleanKeyFrame KeyTime="0:0:0" Value="True" />
|
||||||
|
</BooleanAnimationUsingKeyFrames>
|
||||||
|
</Storyboard>
|
||||||
|
</BeginStoryboard>
|
||||||
|
</EventTrigger.Actions>
|
||||||
|
</EventTrigger>
|
||||||
|
</Style.Triggers>
|
||||||
|
</Style>
|
||||||
|
</Button.Style>
|
||||||
|
<Button.ContextMenu>
|
||||||
|
<ContextMenu>
|
||||||
|
<ContextMenu.Resources>
|
||||||
|
<Converters:InverseBooleanConverter x:Key="InverseBooleanConverter" />
|
||||||
|
</ContextMenu.Resources>
|
||||||
|
<MenuItem Header="Start"
|
||||||
|
Command="{s:Action EnableSegment}"
|
||||||
|
CommandParameter="Start"
|
||||||
|
IsEnabled="{Binding Data.StartSegmentEnabled, Converter={StaticResource InverseBooleanConverter}, Source={StaticResource DataContextProxy}}" />
|
||||||
|
<MenuItem Header="Main"
|
||||||
|
Command="{s:Action EnableSegment}"
|
||||||
|
CommandParameter="Main"
|
||||||
|
IsEnabled="{Binding Data.MainSegmentEnabled, Converter={StaticResource InverseBooleanConverter}, Source={StaticResource DataContextProxy}}" />
|
||||||
|
<MenuItem Header="End"
|
||||||
|
Command="{s:Action EnableSegment}"
|
||||||
|
CommandParameter="End"
|
||||||
|
IsEnabled="{Binding Data.EndSegmentEnabled, Converter={StaticResource InverseBooleanConverter}, Source={StaticResource DataContextProxy}}" />
|
||||||
|
</ContextMenu>
|
||||||
|
</Button.ContextMenu>
|
||||||
|
<TextBlock FontSize="11">
|
||||||
|
ADD SEGMENT
|
||||||
|
</TextBlock>
|
||||||
|
</Button>
|
||||||
|
|
||||||
<!-- Zoom control -->
|
<!-- Zoom control -->
|
||||||
<Slider Grid.Column="1"
|
<Slider Grid.Column="1"
|
||||||
@ -371,7 +434,7 @@
|
|||||||
Maximum="350"
|
Maximum="350"
|
||||||
TickFrequency="1"
|
TickFrequency="1"
|
||||||
IsSnapToTickEnabled="True"
|
IsSnapToTickEnabled="True"
|
||||||
AutoToolTipPlacement="TopLeft"
|
AutoToolTipPlacement="TopLeft"
|
||||||
Value="{Binding ProfileEditorService.PixelsPerSecond}"
|
Value="{Binding ProfileEditorService.PixelsPerSecond}"
|
||||||
Width="319" />
|
Width="319" />
|
||||||
|
|
||||||
|
|||||||
@ -102,27 +102,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
|||||||
public Layer SelectedLayer => SelectedProfileElement as Layer;
|
public Layer SelectedLayer => SelectedProfileElement as Layer;
|
||||||
public Folder SelectedFolder => SelectedProfileElement as Folder;
|
public Folder SelectedFolder => SelectedProfileElement as Folder;
|
||||||
|
|
||||||
public bool StartSegmentEnabled
|
|
||||||
{
|
|
||||||
get => SelectedProfileElement?.StartSegmentLength != TimeSpan.Zero;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
SelectedProfileElement.StartSegmentLength = value ? TimeSpan.FromSeconds(1) : TimeSpan.Zero;
|
|
||||||
ProfileEditorService.UpdateSelectedProfileElement();
|
|
||||||
NotifyOfPropertyChange(nameof(StartSegmentEnabled));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public bool EndSegmentEnabled
|
|
||||||
{
|
|
||||||
get => SelectedProfileElement?.EndSegmentLength != TimeSpan.Zero;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
SelectedProfileElement.EndSegmentLength = value ? TimeSpan.FromSeconds(1) : TimeSpan.Zero;
|
|
||||||
ProfileEditorService.UpdateSelectedProfileElement();
|
|
||||||
NotifyOfPropertyChange(nameof(EndSegmentEnabled));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public BindableCollection<LayerPropertyGroupViewModel> LayerPropertyGroups
|
public BindableCollection<LayerPropertyGroupViewModel> LayerPropertyGroups
|
||||||
{
|
{
|
||||||
@ -586,10 +565,79 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
|||||||
|
|
||||||
#region Segments
|
#region Segments
|
||||||
|
|
||||||
|
public bool StartSegmentEnabled
|
||||||
|
{
|
||||||
|
get => SelectedProfileElement?.StartSegmentLength != TimeSpan.Zero;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SelectedProfileElement.StartSegmentLength = value ? TimeSpan.FromSeconds(1) : TimeSpan.Zero;
|
||||||
|
ProfileEditorService.UpdateSelectedProfileElement();
|
||||||
|
NotifyOfPropertyChange(nameof(StartSegmentEnabled));
|
||||||
|
NotifyOfPropertyChange(nameof(CanAddSegment));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool MainSegmentEnabled
|
||||||
|
{
|
||||||
|
get => SelectedProfileElement?.MainSegmentLength != TimeSpan.Zero;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SelectedProfileElement.MainSegmentLength = value ? TimeSpan.FromSeconds(1) : TimeSpan.Zero;
|
||||||
|
ProfileEditorService.UpdateSelectedProfileElement();
|
||||||
|
NotifyOfPropertyChange(nameof(MainSegmentEnabled));
|
||||||
|
NotifyOfPropertyChange(nameof(CanAddSegment));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool EndSegmentEnabled
|
||||||
|
{
|
||||||
|
get => SelectedProfileElement?.EndSegmentLength != TimeSpan.Zero;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SelectedProfileElement.EndSegmentLength = value ? TimeSpan.FromSeconds(1) : TimeSpan.Zero;
|
||||||
|
ProfileEditorService.UpdateSelectedProfileElement();
|
||||||
|
NotifyOfPropertyChange(nameof(EndSegmentEnabled));
|
||||||
|
NotifyOfPropertyChange(nameof(CanAddSegment));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool CanAddSegment => !StartSegmentEnabled || !MainSegmentEnabled || !EndSegmentEnabled;
|
||||||
|
|
||||||
|
public bool RepeatMainSegment
|
||||||
|
{
|
||||||
|
get => SelectedProfileElement?.RepeatMainSegment ?? false;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
SelectedProfileElement.RepeatMainSegment = value;
|
||||||
|
ProfileEditorService.UpdateSelectedProfileElement();
|
||||||
|
NotifyOfPropertyChange(nameof(RepeatMainSegment));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private bool _draggingStartSegment;
|
private bool _draggingStartSegment;
|
||||||
private bool _draggingMainSegment;
|
private bool _draggingMainSegment;
|
||||||
private bool _draggingEndSegment;
|
private bool _draggingEndSegment;
|
||||||
|
|
||||||
|
public void DisableSegment(string segment)
|
||||||
|
{
|
||||||
|
if (segment == "Start")
|
||||||
|
StartSegmentEnabled = false;
|
||||||
|
else if (segment == "Main")
|
||||||
|
MainSegmentEnabled = false;
|
||||||
|
else if (segment == "End")
|
||||||
|
EndSegmentEnabled = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void EnableSegment(string segment)
|
||||||
|
{
|
||||||
|
if (segment == "Start")
|
||||||
|
StartSegmentEnabled = true;
|
||||||
|
else if (segment == "Main")
|
||||||
|
MainSegmentEnabled = true;
|
||||||
|
else if (segment == "End")
|
||||||
|
EndSegmentEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
public void StartSegmentMouseDown(object sender, MouseButtonEventArgs e)
|
public void StartSegmentMouseDown(object sender, MouseButtonEventArgs e)
|
||||||
{
|
{
|
||||||
((IInputElement) sender).CaptureMouse();
|
((IInputElement) sender).CaptureMouse();
|
||||||
|
|||||||
@ -54,8 +54,15 @@
|
|||||||
</ComboBox.ItemTemplate>
|
</ComboBox.ItemTemplate>
|
||||||
</ComboBox>
|
</ComboBox>
|
||||||
</Grid>
|
</Grid>
|
||||||
<TreeView Grid.Row="1" ItemsSource="{Binding MainDataModel.Children}" HorizontalContentAlignment="Stretch">
|
<TreeView Grid.Row="1"
|
||||||
|
ItemsSource="{Binding MainDataModel.Children}" HorizontalContentAlignment="Stretch"
|
||||||
|
VirtualizingStackPanel.IsVirtualizing="True"
|
||||||
|
VirtualizingStackPanel.VirtualizationMode="Recycling">
|
||||||
<TreeView.Resources>
|
<TreeView.Resources>
|
||||||
|
<Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource MaterialDesignTreeViewItem}">
|
||||||
|
<Setter Property="IsExpanded" Value="{Binding IsVisualizationExpanded, Mode=TwoWay}">
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
<HierarchicalDataTemplate DataType="{x:Type dataModel:DataModelPropertiesViewModel}" ItemsSource="{Binding Children}">
|
<HierarchicalDataTemplate DataType="{x:Type dataModel:DataModelPropertiesViewModel}" ItemsSource="{Binding Children}">
|
||||||
<TextBlock Text="{Binding PropertyDescription.Name}" ToolTip="{Binding PropertyDescription.Description}" />
|
<TextBlock Text="{Binding PropertyDescription.Name}" ToolTip="{Binding PropertyDescription.Description}" />
|
||||||
</HierarchicalDataTemplate>
|
</HierarchicalDataTemplate>
|
||||||
|
|||||||
@ -1,29 +1,36 @@
|
|||||||
using Artemis.Core.Services;
|
using System.Windows;
|
||||||
|
using System.Windows.Interop;
|
||||||
|
using Artemis.Core;
|
||||||
|
using Artemis.Core.Services;
|
||||||
using Artemis.Core.Services.Interfaces;
|
using Artemis.Core.Services.Interfaces;
|
||||||
using Artemis.Core.Utilities;
|
using Artemis.Core.Utilities;
|
||||||
using Artemis.UI.Events;
|
using Artemis.UI.Events;
|
||||||
using Artemis.UI.Screens.Splash;
|
using Artemis.UI.Screens.Splash;
|
||||||
using Artemis.UI.Shared.Controls;
|
using Artemis.UI.Shared.Controls;
|
||||||
using Artemis.UI.Shared.Services.Interfaces;
|
using Artemis.UI.Shared.Services.Interfaces;
|
||||||
|
using MaterialDesignExtensions.Controls;
|
||||||
using Ninject;
|
using Ninject;
|
||||||
using Stylet;
|
using Stylet;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens
|
namespace Artemis.UI.Screens
|
||||||
{
|
{
|
||||||
public class TrayViewModel : Screen
|
public class TrayViewModel : PropertyChangedBase, IViewAware
|
||||||
{
|
{
|
||||||
private readonly IEventAggregator _eventAggregator;
|
private readonly IEventAggregator _eventAggregator;
|
||||||
|
private readonly ICoreService _coreService;
|
||||||
private readonly IKernel _kernel;
|
private readonly IKernel _kernel;
|
||||||
private readonly IWindowManager _windowManager;
|
private readonly IWindowManager _windowManager;
|
||||||
private bool _setGradientPickerService;
|
private bool _setGradientPickerService;
|
||||||
private SplashViewModel _splashViewModel;
|
private SplashViewModel _splashViewModel;
|
||||||
private bool _canShowRootViewModel;
|
private bool _canShowRootViewModel;
|
||||||
|
private UIElement _view;
|
||||||
|
|
||||||
public TrayViewModel(IKernel kernel, IWindowManager windowManager, IEventAggregator eventAggregator, ICoreService coreService, ISettingsService settingsService)
|
public TrayViewModel(IKernel kernel, IWindowManager windowManager, IEventAggregator eventAggregator, ICoreService coreService, ISettingsService settingsService)
|
||||||
{
|
{
|
||||||
_kernel = kernel;
|
_kernel = kernel;
|
||||||
_windowManager = windowManager;
|
_windowManager = windowManager;
|
||||||
_eventAggregator = eventAggregator;
|
_eventAggregator = eventAggregator;
|
||||||
|
_coreService = coreService;
|
||||||
CanShowRootViewModel = true;
|
CanShowRootViewModel = true;
|
||||||
|
|
||||||
var autoRunning = Bootstrapper.StartupArguments.Contains("--autorun");
|
var autoRunning = Bootstrapper.StartupArguments.Contains("--autorun");
|
||||||
@ -89,5 +96,15 @@ namespace Artemis.UI.Screens
|
|||||||
{
|
{
|
||||||
CanShowRootViewModel = true;
|
CanShowRootViewModel = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void AttachView(UIElement view)
|
||||||
|
{
|
||||||
|
View = view;
|
||||||
|
|
||||||
|
var handle = new WindowInteropHelper((Window) view).EnsureHandle();
|
||||||
|
_coreService.SetMainWindowHandle(handle);
|
||||||
|
}
|
||||||
|
|
||||||
|
public UIElement View { get; set; }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -12,6 +12,7 @@ namespace Artemis.Plugins.LayerEffects.Filter
|
|||||||
"BlurOn"
|
"BlurOn"
|
||||||
);
|
);
|
||||||
AddLayerEffectDescriptor<DilateEffect>("Dilate", "A layer effect providing a dilation filter effect", "EyePlus");
|
AddLayerEffectDescriptor<DilateEffect>("Dilate", "A layer effect providing a dilation filter effect", "EyePlus");
|
||||||
|
AddLayerEffectDescriptor<OpacityEffect>("Opacity", "A layer effect letting you change the opacity of all children", "Opacity");
|
||||||
AddLayerEffectDescriptor<ErodeEffect>("Erode", "A layer effect providing an erode filter effect", "EyeMinus");
|
AddLayerEffectDescriptor<ErodeEffect>("Erode", "A layer effect providing an erode filter effect", "EyeMinus");
|
||||||
AddLayerEffectDescriptor<GlowEffect>("Glow", "A layer effect providing a glow filter effect", "BoxShadow");
|
AddLayerEffectDescriptor<GlowEffect>("Glow", "A layer effect providing a glow filter effect", "BoxShadow");
|
||||||
AddLayerEffectDescriptor<GrayScaleEffect>("Gray-scale", "A layer effect providing a gray-scale filter effect", "InvertColors");
|
AddLayerEffectDescriptor<GrayScaleEffect>("Gray-scale", "A layer effect providing a gray-scale filter effect", "InvertColors");
|
||||||
|
|||||||
@ -0,0 +1,47 @@
|
|||||||
|
using Artemis.Core.Models.Profile;
|
||||||
|
using Artemis.Core.Models.Profile.LayerProperties.Attributes;
|
||||||
|
using Artemis.Core.Models.Profile.LayerProperties.Types;
|
||||||
|
using Artemis.Core.Plugins.LayerEffect.Abstract;
|
||||||
|
using SkiaSharp;
|
||||||
|
|
||||||
|
namespace Artemis.Plugins.LayerEffects.Filter
|
||||||
|
{
|
||||||
|
public class OpacityEffect : LayerEffect<OpacityEffectProperties>
|
||||||
|
{
|
||||||
|
public override void EnableLayerEffect()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void DisableLayerEffect()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Update(double deltaTime)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PreProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath renderBounds, SKPaint paint)
|
||||||
|
{
|
||||||
|
paint.Color = paint.Color.WithAlpha((byte) (Properties.Opacity.CurrentValue * 2.55f));
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void PostProcess(SKCanvas canvas, SKImageInfo canvasInfo, SKPath renderBounds, SKPaint paint)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class OpacityEffectProperties : LayerPropertyGroup
|
||||||
|
{
|
||||||
|
[PropertyDescription(Description = "The opacity of the shape", InputAffix = "%", MinInputValue = 0f, MaxInputValue = 100f)]
|
||||||
|
public FloatLayerProperty Opacity { get; set; }
|
||||||
|
|
||||||
|
protected override void PopulateDefaults()
|
||||||
|
{
|
||||||
|
Opacity.DefaultValue = 100f;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override void OnPropertiesInitialized()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,13 +1,27 @@
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Artemis.Core.Plugins.Abstract.DataModels;
|
using System.Diagnostics;
|
||||||
using Artemis.Core.Plugins.Abstract.DataModels.Attributes;
|
using Artemis.Core.Plugins.Abstract.DataModels.Attributes;
|
||||||
|
using Artemis.Plugins.Modules.General.DataModel.Windows;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
namespace Artemis.Plugins.Modules.General
|
namespace Artemis.Plugins.Modules.General.DataModel
|
||||||
{
|
{
|
||||||
public class GeneralDataModel : DataModel
|
public class GeneralDataModel : Core.Plugins.Abstract.DataModels.DataModel
|
||||||
{
|
{
|
||||||
|
public TestDataModel TestDataModel { get; set; }
|
||||||
|
public WindowsDataModel Windows { get; set; }
|
||||||
|
|
||||||
|
|
||||||
public GeneralDataModel()
|
public GeneralDataModel()
|
||||||
|
{
|
||||||
|
TestDataModel = new TestDataModel();
|
||||||
|
Windows = new WindowsDataModel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class TestDataModel
|
||||||
|
{
|
||||||
|
public TestDataModel()
|
||||||
{
|
{
|
||||||
PlayerInfo = new PlayerInfo();
|
PlayerInfo = new PlayerInfo();
|
||||||
IntsList = new List<int>();
|
IntsList = new List<int>();
|
||||||
@ -0,0 +1,26 @@
|
|||||||
|
using System.Diagnostics;
|
||||||
|
using Artemis.Core.Plugins.Abstract.DataModels.Attributes;
|
||||||
|
using Artemis.Plugins.Modules.General.Utilities;
|
||||||
|
|
||||||
|
namespace Artemis.Plugins.Modules.General.DataModel.Windows
|
||||||
|
{
|
||||||
|
public class WindowDataModel
|
||||||
|
{
|
||||||
|
[DataModelIgnore]
|
||||||
|
public Process Process { get; }
|
||||||
|
|
||||||
|
public WindowDataModel(Process process)
|
||||||
|
{
|
||||||
|
Process = process;
|
||||||
|
WindowTitle = process.MainWindowTitle;
|
||||||
|
ProcessName = process.ProcessName;
|
||||||
|
|
||||||
|
// Accessing MainModule requires admin privileges, this way does not
|
||||||
|
ProgramLocation = WindowMonitor.GetProcessFilename(process);
|
||||||
|
}
|
||||||
|
|
||||||
|
public string WindowTitle { get; set; }
|
||||||
|
public string ProcessName { get; set; }
|
||||||
|
public string ProgramLocation { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -0,0 +1,12 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Artemis.Plugins.Modules.General.DataModel.Windows
|
||||||
|
{
|
||||||
|
public class WindowsDataModel
|
||||||
|
{
|
||||||
|
public WindowDataModel ActiveWindow { get; set; }
|
||||||
|
public List<WindowDataModel> OpenWindows { get; set; }
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,8 +1,16 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Interop;
|
||||||
|
using Artemis.Core;
|
||||||
using Artemis.Core.Plugins.Abstract;
|
using Artemis.Core.Plugins.Abstract;
|
||||||
using Artemis.Core.Plugins.Abstract.ViewModels;
|
using Artemis.Core.Plugins.Abstract.ViewModels;
|
||||||
using Artemis.Core.Plugins.Models;
|
using Artemis.Core.Plugins.Models;
|
||||||
|
using Artemis.Plugins.Modules.General.DataModel;
|
||||||
|
using Artemis.Plugins.Modules.General.DataModel.Windows;
|
||||||
|
using Artemis.Plugins.Modules.General.Utilities;
|
||||||
using Artemis.Plugins.Modules.General.ViewModels;
|
using Artemis.Plugins.Modules.General.ViewModels;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
@ -13,6 +21,7 @@ namespace Artemis.Plugins.Modules.General
|
|||||||
private readonly PluginSettings _settings;
|
private readonly PluginSettings _settings;
|
||||||
private readonly Random _rand;
|
private readonly Random _rand;
|
||||||
|
|
||||||
|
|
||||||
public GeneralModule(PluginSettings settings)
|
public GeneralModule(PluginSettings settings)
|
||||||
{
|
{
|
||||||
_settings = settings;
|
_settings = settings;
|
||||||
@ -26,12 +35,19 @@ namespace Artemis.Plugins.Modules.General
|
|||||||
|
|
||||||
public override void Update(double deltaTime)
|
public override void Update(double deltaTime)
|
||||||
{
|
{
|
||||||
DataModel.UpdatesDividedByFour += 0.25;
|
DataModel.TestDataModel.UpdatesDividedByFour += 0.25;
|
||||||
DataModel.Updates += 1;
|
DataModel.TestDataModel.Updates += 1;
|
||||||
DataModel.PlayerInfo.Position = new SKPoint(_rand.Next(100), _rand.Next(100));
|
DataModel.TestDataModel.PlayerInfo.Position = new SKPoint(_rand.Next(100), _rand.Next(100));
|
||||||
|
DataModel.TestDataModel.PlayerInfo.Health++;
|
||||||
|
if (DataModel.TestDataModel.PlayerInfo.Health > 200)
|
||||||
|
DataModel.TestDataModel.PlayerInfo.Health = 0;
|
||||||
|
|
||||||
|
DataModel.TestDataModel.IntsList[0] = _rand.Next();
|
||||||
|
DataModel.TestDataModel.IntsList[2] = _rand.Next();
|
||||||
|
|
||||||
|
UpdateCurrentWindow();
|
||||||
|
UpdateBackgroundWindows();
|
||||||
|
|
||||||
DataModel.IntsList[0] = _rand.Next();
|
|
||||||
DataModel.IntsList[2] = _rand.Next();
|
|
||||||
base.Update(deltaTime);
|
base.Update(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,8 +57,8 @@ namespace Artemis.Plugins.Modules.General
|
|||||||
DisplayIcon = "AllInclusive";
|
DisplayIcon = "AllInclusive";
|
||||||
ExpandsDataModel = true;
|
ExpandsDataModel = true;
|
||||||
|
|
||||||
DataModel.IntsList = new List<int> {_rand.Next(), _rand.Next(), _rand.Next()};
|
DataModel.TestDataModel.IntsList = new List<int> {_rand.Next(), _rand.Next(), _rand.Next()};
|
||||||
DataModel.PlayerInfosList = new List<PlayerInfo> {new PlayerInfo()};
|
DataModel.TestDataModel.PlayerInfosList = new List<PlayerInfo> {new PlayerInfo()};
|
||||||
|
|
||||||
var testSetting = _settings.GetSetting("TestSetting", DateTime.Now);
|
var testSetting = _settings.GetSetting("TestSetting", DateTime.Now);
|
||||||
}
|
}
|
||||||
@ -50,5 +66,36 @@ namespace Artemis.Plugins.Modules.General
|
|||||||
public override void DisablePlugin()
|
public override void DisablePlugin()
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#region Open windows
|
||||||
|
|
||||||
|
private DateTime _lastBackgroundWindowsUpdate;
|
||||||
|
|
||||||
|
public void UpdateCurrentWindow()
|
||||||
|
{
|
||||||
|
var processId = WindowMonitor.GetActiveProcessId();
|
||||||
|
if (DataModel.Windows.ActiveWindow == null || DataModel.Windows.ActiveWindow.Process.Id != processId)
|
||||||
|
DataModel.Windows.ActiveWindow = new WindowDataModel(Process.GetProcessById(processId));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void UpdateBackgroundWindows()
|
||||||
|
{
|
||||||
|
// This is kinda slow so lets not do it very often and lets do it in a task
|
||||||
|
if (DateTime.Now - _lastBackgroundWindowsUpdate < TimeSpan.FromSeconds(5))
|
||||||
|
return;
|
||||||
|
|
||||||
|
_lastBackgroundWindowsUpdate = DateTime.Now;
|
||||||
|
Task.Run(() =>
|
||||||
|
{
|
||||||
|
// All processes with a main window handle are considered open windows
|
||||||
|
DataModel.Windows.OpenWindows = Process.GetProcesses()
|
||||||
|
.Where(p => p.MainWindowHandle != IntPtr.Zero)
|
||||||
|
.Select(p => new WindowDataModel(p))
|
||||||
|
.Where(w => !string.IsNullOrEmpty(w.WindowTitle))
|
||||||
|
.ToList();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -0,0 +1,46 @@
|
|||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace Artemis.Plugins.Modules.General.Utilities
|
||||||
|
{
|
||||||
|
public static class WindowMonitor
|
||||||
|
{
|
||||||
|
public static int GetActiveProcessId()
|
||||||
|
{
|
||||||
|
var hWnd = GetForegroundWindow(); // Get foreground window handle
|
||||||
|
GetWindowThreadProcessId(hWnd, out var processId);
|
||||||
|
return (int) processId;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string GetProcessFilename(Process p)
|
||||||
|
{
|
||||||
|
var capacity = 2000;
|
||||||
|
var builder = new StringBuilder(capacity);
|
||||||
|
var ptr = OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, p.Id);
|
||||||
|
if (!QueryFullProcessImageName(ptr, 0, builder, ref capacity)) return string.Empty;
|
||||||
|
|
||||||
|
return builder.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern IntPtr GetForegroundWindow();
|
||||||
|
|
||||||
|
[DllImport("user32.dll")]
|
||||||
|
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll")]
|
||||||
|
private static extern bool QueryFullProcessImageName([In] IntPtr hProcess, [In] int dwFlags, [Out] StringBuilder lpExeName, ref int lpdwSize);
|
||||||
|
|
||||||
|
[DllImport("kernel32.dll")]
|
||||||
|
private static extern IntPtr OpenProcess(ProcessAccessFlags processAccess, bool bInheritHandle, int processId);
|
||||||
|
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
private enum ProcessAccessFlags : uint
|
||||||
|
{
|
||||||
|
QueryLimitedInformation = 0x00001000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
x
Reference in New Issue
Block a user