mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Merge branch 'development'
This commit is contained in:
commit
600b20e5be
@ -14,6 +14,8 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public sealed class Folder : RenderProfileElement
|
||||
{
|
||||
private bool _isExpanded;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new instance of the <see cref="Folder" /> class and adds itself to the child collection of the provided
|
||||
/// <paramref name="parent" />
|
||||
@ -46,6 +48,7 @@ namespace Artemis.Core
|
||||
Profile = profile;
|
||||
Parent = parent;
|
||||
Name = folderEntity.Name;
|
||||
IsExpanded = folderEntity.IsExpanded;
|
||||
Suspended = folderEntity.Suspended;
|
||||
Order = folderEntity.Order;
|
||||
|
||||
@ -57,6 +60,15 @@ namespace Artemis.Core
|
||||
/// </summary>
|
||||
public bool IsRootFolder => Parent == Profile;
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a boolean indicating whether this folder is expanded
|
||||
/// </summary>
|
||||
public bool IsExpanded
|
||||
{
|
||||
get => _isExpanded;
|
||||
set => SetAndNotify(ref _isExpanded, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the folder entity this folder uses for persistent storage
|
||||
/// </summary>
|
||||
@ -72,8 +84,10 @@ namespace Artemis.Core
|
||||
{
|
||||
List<ILayerProperty> result = new();
|
||||
foreach (BaseLayerEffect layerEffect in LayerEffects)
|
||||
{
|
||||
if (layerEffect.BaseProperties != null)
|
||||
result.AddRange(layerEffect.BaseProperties.GetAllLayerProperties());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
@ -151,27 +165,6 @@ namespace Artemis.Core
|
||||
return $"[Folder] {nameof(Name)}: {Name}, {nameof(Order)}: {Order}";
|
||||
}
|
||||
|
||||
internal void CalculateRenderProperties()
|
||||
{
|
||||
if (Disposed)
|
||||
throw new ObjectDisposedException("Folder");
|
||||
|
||||
SKPath path = new() {FillType = SKPathFillType.Winding};
|
||||
foreach (ProfileElement child in Children)
|
||||
{
|
||||
if (child is RenderProfileElement effectChild && effectChild.Path != null)
|
||||
path.AddPath(effectChild.Path);
|
||||
}
|
||||
|
||||
Path = path;
|
||||
|
||||
// Folder render properties are based on child paths and thus require an update
|
||||
if (Parent is Folder folder)
|
||||
folder.CalculateRenderProperties();
|
||||
|
||||
OnRenderPropertiesUpdated();
|
||||
}
|
||||
|
||||
#region Rendering
|
||||
|
||||
/// <inheritdoc />
|
||||
@ -209,7 +202,7 @@ namespace Artemis.Core
|
||||
|
||||
canvas.SaveLayer(layerPaint);
|
||||
canvas.Translate(Bounds.Left - basePosition.X, Bounds.Top - basePosition.Y);
|
||||
|
||||
|
||||
// Iterate the children in reverse because the first layer must be rendered last to end up on top
|
||||
for (int index = Children.Count - 1; index > -1; index--)
|
||||
Children[index].Render(canvas, new SKPointI(Bounds.Left, Bounds.Top));
|
||||
@ -229,57 +222,6 @@ namespace Artemis.Core
|
||||
|
||||
#endregion
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
Disposed = true;
|
||||
|
||||
Disable();
|
||||
foreach (ProfileElement profileElement in Children)
|
||||
profileElement.Dispose();
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
internal override void Load()
|
||||
{
|
||||
ExpandedPropertyGroups.AddRange(FolderEntity.ExpandedPropertyGroups);
|
||||
Reset();
|
||||
|
||||
// Load child folders
|
||||
foreach (FolderEntity childFolder in Profile.ProfileEntity.Folders.Where(f => f.ParentId == EntityId))
|
||||
ChildrenList.Add(new Folder(Profile, this, childFolder));
|
||||
// Load child layers
|
||||
foreach (LayerEntity childLayer in Profile.ProfileEntity.Layers.Where(f => f.ParentId == EntityId))
|
||||
ChildrenList.Add(new Layer(Profile, this, childLayer));
|
||||
|
||||
// Ensure order integrity, should be unnecessary but no one is perfect specially me
|
||||
ChildrenList = ChildrenList.OrderBy(c => c.Order).ToList();
|
||||
for (int index = 0; index < ChildrenList.Count; index++)
|
||||
ChildrenList[index].Order = index + 1;
|
||||
|
||||
LoadRenderElement();
|
||||
}
|
||||
|
||||
internal override void Save()
|
||||
{
|
||||
if (Disposed)
|
||||
throw new ObjectDisposedException("Folder");
|
||||
|
||||
FolderEntity.Id = EntityId;
|
||||
FolderEntity.ParentId = Parent?.EntityId ?? new Guid();
|
||||
|
||||
FolderEntity.Order = Order;
|
||||
FolderEntity.Name = Name;
|
||||
FolderEntity.Suspended = Suspended;
|
||||
|
||||
FolderEntity.ProfileId = Profile.EntityId;
|
||||
FolderEntity.ExpandedPropertyGroups.Clear();
|
||||
FolderEntity.ExpandedPropertyGroups.AddRange(ExpandedPropertyGroups);
|
||||
|
||||
SaveRenderElement();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public override void Enable()
|
||||
{
|
||||
@ -320,18 +262,87 @@ namespace Artemis.Core
|
||||
Enabled = false;
|
||||
}
|
||||
|
||||
#region Events
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when a property affecting the rendering properties of this folder has been updated
|
||||
/// </summary>
|
||||
public event EventHandler? RenderPropertiesUpdated;
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
Disposed = true;
|
||||
|
||||
Disable();
|
||||
foreach (ProfileElement profileElement in Children)
|
||||
profileElement.Dispose();
|
||||
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
internal void CalculateRenderProperties()
|
||||
{
|
||||
if (Disposed)
|
||||
throw new ObjectDisposedException("Folder");
|
||||
|
||||
SKPath path = new() {FillType = SKPathFillType.Winding};
|
||||
foreach (ProfileElement child in Children)
|
||||
{
|
||||
if (child is RenderProfileElement effectChild && effectChild.Path != null)
|
||||
path.AddPath(effectChild.Path);
|
||||
}
|
||||
|
||||
Path = path;
|
||||
|
||||
// Folder render properties are based on child paths and thus require an update
|
||||
if (Parent is Folder folder)
|
||||
folder.CalculateRenderProperties();
|
||||
|
||||
OnRenderPropertiesUpdated();
|
||||
}
|
||||
|
||||
internal override void Load()
|
||||
{
|
||||
ExpandedPropertyGroups.AddRange(FolderEntity.ExpandedPropertyGroups);
|
||||
Reset();
|
||||
|
||||
// Load child folders
|
||||
foreach (FolderEntity childFolder in Profile.ProfileEntity.Folders.Where(f => f.ParentId == EntityId))
|
||||
ChildrenList.Add(new Folder(Profile, this, childFolder));
|
||||
// Load child layers
|
||||
foreach (LayerEntity childLayer in Profile.ProfileEntity.Layers.Where(f => f.ParentId == EntityId))
|
||||
ChildrenList.Add(new Layer(Profile, this, childLayer));
|
||||
|
||||
// Ensure order integrity, should be unnecessary but no one is perfect specially me
|
||||
ChildrenList = ChildrenList.OrderBy(c => c.Order).ToList();
|
||||
for (int index = 0; index < ChildrenList.Count; index++)
|
||||
ChildrenList[index].Order = index + 1;
|
||||
|
||||
LoadRenderElement();
|
||||
}
|
||||
|
||||
internal override void Save()
|
||||
{
|
||||
if (Disposed)
|
||||
throw new ObjectDisposedException("Folder");
|
||||
|
||||
FolderEntity.Id = EntityId;
|
||||
FolderEntity.ParentId = Parent?.EntityId ?? new Guid();
|
||||
|
||||
FolderEntity.Order = Order;
|
||||
FolderEntity.Name = Name;
|
||||
FolderEntity.IsExpanded = IsExpanded;
|
||||
FolderEntity.Suspended = Suspended;
|
||||
|
||||
FolderEntity.ProfileId = Profile.EntityId;
|
||||
FolderEntity.ExpandedPropertyGroups.Clear();
|
||||
FolderEntity.ExpandedPropertyGroups.AddRange(ExpandedPropertyGroups);
|
||||
|
||||
SaveRenderElement();
|
||||
}
|
||||
|
||||
private void OnRenderPropertiesUpdated()
|
||||
{
|
||||
RenderPropertiesUpdated?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -14,6 +14,7 @@ namespace Artemis.Core
|
||||
{
|
||||
private readonly object _lock = new();
|
||||
private bool _isFreshImport;
|
||||
private ProfileElement? _lastSelectedProfileElement;
|
||||
|
||||
internal Profile(ProfileConfiguration configuration, ProfileEntity profileEntity) : base(null!)
|
||||
{
|
||||
@ -60,6 +61,15 @@ namespace Artemis.Core
|
||||
set => SetAndNotify(ref _isFreshImport, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the last selected profile element of this profile
|
||||
/// </summary>
|
||||
public ProfileElement? LastSelectedProfileElement
|
||||
{
|
||||
get => _lastSelectedProfileElement;
|
||||
set => SetAndNotify(ref _lastSelectedProfileElement, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the profile entity this profile uses for persistent storage
|
||||
/// </summary>
|
||||
@ -187,6 +197,15 @@ namespace Artemis.Core
|
||||
}
|
||||
}
|
||||
|
||||
if (ProfileEntity.LastSelectedProfileElement != Guid.Empty)
|
||||
{
|
||||
LastSelectedProfileElement = GetAllFolders().FirstOrDefault(f => f.EntityId == ProfileEntity.LastSelectedProfileElement);
|
||||
if (LastSelectedProfileElement == null)
|
||||
LastSelectedProfileElement = GetAllLayers().FirstOrDefault(f => f.EntityId == ProfileEntity.LastSelectedProfileElement);
|
||||
}
|
||||
else
|
||||
LastSelectedProfileElement = null;
|
||||
|
||||
foreach (ScriptConfiguration scriptConfiguration in ScriptConfigurations)
|
||||
scriptConfiguration.Script?.Dispose();
|
||||
ScriptConfigurations.Clear();
|
||||
@ -201,6 +220,7 @@ namespace Artemis.Core
|
||||
ProfileEntity.Id = EntityId;
|
||||
ProfileEntity.Name = Configuration.Name;
|
||||
ProfileEntity.IsFreshImport = IsFreshImport;
|
||||
ProfileEntity.LastSelectedProfileElement = LastSelectedProfileElement?.EntityId ?? Guid.Empty;
|
||||
|
||||
foreach (ProfileElement profileElement in Children)
|
||||
profileElement.Save();
|
||||
|
||||
@ -397,7 +397,7 @@ namespace Artemis.Core
|
||||
if (conditionMet && !DisplayConditionMet && Timeline.IsFinished)
|
||||
Timeline.JumpToStart();
|
||||
// If regular conditions are no longer met, jump to the end segment if stop mode requires it
|
||||
if (!conditionMet && DisplayConditionMet && Timeline.StopMode == TimelineStopMode.SkipToEnd)
|
||||
if (!conditionMet && Timeline.StopMode == TimelineStopMode.SkipToEnd)
|
||||
Timeline.JumpToEndSegment();
|
||||
}
|
||||
else if (conditionMet)
|
||||
|
||||
@ -179,7 +179,8 @@ namespace Artemis.Core
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException("ProfileConfiguration");
|
||||
|
||||
if (IsBeingEdited)
|
||||
return true;
|
||||
if (Category.IsSuspended || IsSuspended || IsMissingModule)
|
||||
return false;
|
||||
|
||||
|
||||
@ -209,14 +209,15 @@ namespace Artemis.Core.Services
|
||||
ProcessPendingKeyEvents(profileConfiguration);
|
||||
|
||||
// Profiles being edited are updated at their own leisure
|
||||
if (profileConfiguration.IsBeingEdited)
|
||||
if (profileConfiguration.IsBeingEdited && RenderForEditor)
|
||||
continue;
|
||||
|
||||
bool shouldBeActive = profileConfiguration.ShouldBeActive(false);
|
||||
if (shouldBeActive)
|
||||
{
|
||||
profileConfiguration.Update();
|
||||
shouldBeActive = profileConfiguration.ActivationConditionMet;
|
||||
if (!profileConfiguration.IsBeingEdited)
|
||||
shouldBeActive = profileConfiguration.ActivationConditionMet;
|
||||
}
|
||||
|
||||
try
|
||||
@ -245,6 +246,16 @@ namespace Artemis.Core.Services
|
||||
{
|
||||
lock (_profileCategories)
|
||||
{
|
||||
ProfileConfiguration? editedProfileConfiguration = _profileCategories.SelectMany(c => c.ProfileConfigurations).FirstOrDefault(p => p.IsBeingEdited);
|
||||
if (editedProfileConfiguration != null)
|
||||
{
|
||||
editedProfileConfiguration.Profile?.Render(canvas, SKPointI.Empty);
|
||||
return;
|
||||
}
|
||||
|
||||
if (RenderForEditor)
|
||||
return;
|
||||
|
||||
// Iterate the children in reverse because the first category must be rendered last to end up on top
|
||||
for (int i = _profileCategories.Count - 1; i > -1; i--)
|
||||
{
|
||||
@ -254,17 +265,9 @@ namespace Artemis.Core.Services
|
||||
try
|
||||
{
|
||||
ProfileConfiguration profileConfiguration = profileCategory.ProfileConfigurations[j];
|
||||
if (RenderForEditor)
|
||||
{
|
||||
if (profileConfiguration.IsBeingEdited)
|
||||
profileConfiguration.Profile?.Render(canvas, SKPointI.Empty);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Ensure all criteria are met before rendering
|
||||
if (!profileConfiguration.IsSuspended && !profileConfiguration.IsMissingModule && profileConfiguration.ActivationConditionMet)
|
||||
profileConfiguration.Profile?.Render(canvas, SKPointI.Empty);
|
||||
}
|
||||
// Ensure all criteria are met before rendering
|
||||
if (!profileConfiguration.IsSuspended && !profileConfiguration.IsMissingModule && profileConfiguration.ActivationConditionMet)
|
||||
profileConfiguration.Profile?.Render(canvas, SKPointI.Empty);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
@ -396,13 +399,6 @@ namespace Artemis.Core.Services
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new profile configuration and adds it to the provided <see cref="ProfileCategory" />
|
||||
/// </summary>
|
||||
/// <param name="category">The profile category to add the profile to</param>
|
||||
/// <param name="name">The name of the new profile configuration</param>
|
||||
/// <param name="icon">The icon of the new profile configuration</param>
|
||||
/// <returns>The newly created profile configuration</returns>
|
||||
public ProfileConfiguration CreateProfileConfiguration(ProfileCategory category, string name, string icon)
|
||||
{
|
||||
ProfileConfiguration configuration = new(category, name, icon);
|
||||
@ -414,10 +410,6 @@ namespace Artemis.Core.Services
|
||||
return configuration;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Removes the provided profile configuration from the <see cref="ProfileCategory" />
|
||||
/// </summary>
|
||||
/// <param name="profileConfiguration"></param>
|
||||
public void RemoveProfileConfiguration(ProfileConfiguration profileConfiguration)
|
||||
{
|
||||
profileConfiguration.Category.RemoveProfileConfiguration(profileConfiguration);
|
||||
|
||||
@ -16,6 +16,7 @@ namespace Artemis.Storage.Entities.Profile
|
||||
|
||||
public int Order { get; set; }
|
||||
public string Name { get; set; }
|
||||
public bool IsExpanded { get; set; }
|
||||
public bool Suspended { get; set; }
|
||||
|
||||
[BsonRef("ProfileEntity")]
|
||||
|
||||
@ -18,6 +18,7 @@ namespace Artemis.Storage.Entities.Profile
|
||||
|
||||
public string Name { get; set; }
|
||||
public bool IsFreshImport { get; set; }
|
||||
public Guid LastSelectedProfileElement { get; set; }
|
||||
|
||||
public List<FolderEntity> Folders { get; set; }
|
||||
public List<LayerEntity> Layers { get; set; }
|
||||
|
||||
@ -27,12 +27,12 @@ namespace Artemis.UI.Shared
|
||||
/// <summary>
|
||||
/// Gets or sets the minimum value
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MinProperty = DependencyProperty.Register(nameof(Min), typeof(float?), typeof(DraggableFloat));
|
||||
public static readonly DependencyProperty MinProperty = DependencyProperty.Register(nameof(Min), typeof(object), typeof(DraggableFloat));
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum value
|
||||
/// </summary>
|
||||
public static readonly DependencyProperty MaxProperty = DependencyProperty.Register(nameof(Max), typeof(float?), typeof(DraggableFloat));
|
||||
public static readonly DependencyProperty MaxProperty = DependencyProperty.Register(nameof(Max), typeof(object), typeof(DraggableFloat));
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the value has changed
|
||||
@ -90,18 +90,18 @@ namespace Artemis.UI.Shared
|
||||
/// <summary>
|
||||
/// Gets or sets the minimum value
|
||||
/// </summary>
|
||||
public float? Min
|
||||
public object? Min
|
||||
{
|
||||
get => (float?) GetValue(MinProperty);
|
||||
get => (object?) GetValue(MinProperty);
|
||||
set => SetValue(MinProperty, value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the maximum value
|
||||
/// </summary>
|
||||
public float? Max
|
||||
public object? Max
|
||||
{
|
||||
get => (float?) GetValue(MaxProperty);
|
||||
get => (object?) GetValue(MaxProperty);
|
||||
set => SetValue(MaxProperty, value);
|
||||
}
|
||||
|
||||
@ -207,10 +207,11 @@ namespace Artemis.UI.Shared
|
||||
stepSize = stepSize * 10;
|
||||
|
||||
float value = (float) RoundToNearestOf(startValue + stepSize * (x - startX), stepSize);
|
||||
if (Min != null)
|
||||
value = Math.Max(value, Min.Value);
|
||||
if (Max != null)
|
||||
value = Math.Min(value, Max.Value);
|
||||
|
||||
if (Min != null && float.TryParse(Min.ToString(), out float minFloat))
|
||||
value = Math.Max(value, minFloat);
|
||||
if (Max != null && float.TryParse(Max.ToString(), out float maxFloat))
|
||||
value = Math.Min(value, maxFloat);
|
||||
|
||||
Value = value;
|
||||
}
|
||||
|
||||
@ -17,9 +17,17 @@ namespace Artemis.UI.Shared.Services
|
||||
/// </summary>
|
||||
ProfileConfiguration? SelectedProfileConfiguration { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the previous selected profile configuration
|
||||
/// </summary>
|
||||
ProfileConfiguration? PreviousSelectedProfileConfiguration { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the currently selected profile
|
||||
/// <para><see langword="null" /> if the editor is closed, always equal to <see cref="SelectedProfileConfiguration" />.<see cref="Profile" /></para>
|
||||
/// <para>
|
||||
/// <see langword="null" /> if the editor is closed, always equal to <see cref="SelectedProfileConfiguration" />.
|
||||
/// <see cref="Profile" />
|
||||
/// </para>
|
||||
/// </summary>
|
||||
Profile? SelectedProfile { get; }
|
||||
|
||||
@ -53,6 +61,11 @@ namespace Artemis.UI.Shared.Services
|
||||
/// </summary>
|
||||
bool Playing { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets a boolean indicating whether editing should be suspended
|
||||
/// </summary>
|
||||
bool SuspendEditing { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Changes the selected profile by its <see cref="ProfileConfiguration" />
|
||||
/// </summary>
|
||||
@ -214,6 +227,12 @@ namespace Artemis.UI.Shared.Services
|
||||
/// </summary>
|
||||
event EventHandler PixelsPerSecondChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the suspend editing boolean is changed
|
||||
/// </summary>
|
||||
|
||||
event EventHandler SuspendEditingChanged;
|
||||
|
||||
/// <summary>
|
||||
/// Occurs when the profile preview has been updated
|
||||
/// </summary>
|
||||
|
||||
@ -4,7 +4,6 @@ using System.Collections.ObjectModel;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Modules;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.Storage.Entities.Profile;
|
||||
using Artemis.UI.Shared.Services.Models;
|
||||
@ -30,6 +29,7 @@ namespace Artemis.UI.Shared.Services
|
||||
private TimeSpan _currentTime;
|
||||
private bool _doTick;
|
||||
private int _pixelsPerSecond;
|
||||
private bool _suspendEditing;
|
||||
|
||||
public ProfileEditorService(IKernel kernel, ILogger logger, IProfileService profileService, ICoreService coreService, IRgbService rgbService, IModuleService moduleService)
|
||||
{
|
||||
@ -76,7 +76,7 @@ namespace Artemis.UI.Shared.Services
|
||||
|
||||
private void Tick()
|
||||
{
|
||||
if (SelectedProfile == null || _doTick)
|
||||
if (SelectedProfile == null || _doTick || SuspendEditing)
|
||||
return;
|
||||
|
||||
TickProfileElement(SelectedProfile.GetRootFolder());
|
||||
@ -106,6 +106,32 @@ namespace Artemis.UI.Shared.Services
|
||||
public ReadOnlyCollection<PropertyInputRegistration> RegisteredPropertyEditors => _registeredPropertyEditors.AsReadOnly();
|
||||
|
||||
public bool Playing { get; set; }
|
||||
|
||||
public bool SuspendEditing
|
||||
{
|
||||
get => _suspendEditing;
|
||||
set
|
||||
{
|
||||
if (_suspendEditing == value)
|
||||
return;
|
||||
|
||||
_suspendEditing = value;
|
||||
if (value)
|
||||
{
|
||||
Playing = false;
|
||||
_profileService.RenderForEditor = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (SelectedProfileConfiguration != null)
|
||||
_profileService.RenderForEditor = true;
|
||||
}
|
||||
|
||||
OnSuspendEditingChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public ProfileConfiguration? PreviousSelectedProfileConfiguration { get; private set; }
|
||||
public ProfileConfiguration? SelectedProfileConfiguration { get; private set; }
|
||||
public Profile? SelectedProfile => SelectedProfileConfiguration?.Profile;
|
||||
public RenderProfileElement? SelectedProfileElement { get; private set; }
|
||||
@ -137,6 +163,9 @@ namespace Artemis.UI.Shared.Services
|
||||
{
|
||||
lock (_selectedProfileLock)
|
||||
{
|
||||
if (SuspendEditing)
|
||||
throw new ArtemisSharedUIException("Cannot change the selected profile while editing is suspended");
|
||||
|
||||
if (SelectedProfileConfiguration == profileConfiguration)
|
||||
return;
|
||||
|
||||
@ -144,21 +173,30 @@ namespace Artemis.UI.Shared.Services
|
||||
throw new ArtemisSharedUIException("Cannot select a disposed profile");
|
||||
|
||||
_logger.Verbose("ChangeSelectedProfileConfiguration {profile}", profileConfiguration);
|
||||
|
||||
if (SelectedProfileConfiguration != null)
|
||||
SaveSelectedProfileConfiguration();
|
||||
|
||||
ChangeSelectedProfileElement(null);
|
||||
ProfileConfigurationEventArgs profileConfigurationElementEvent = new(profileConfiguration, SelectedProfileConfiguration);
|
||||
|
||||
// No need to deactivate the profile, if needed it will be deactivated next update
|
||||
if (SelectedProfileConfiguration != null)
|
||||
SelectedProfileConfiguration.IsBeingEdited = false;
|
||||
|
||||
// The new profile may need activation
|
||||
|
||||
PreviousSelectedProfileConfiguration = SelectedProfileConfiguration;
|
||||
SelectedProfileConfiguration = profileConfiguration;
|
||||
|
||||
// The new profile may need activation
|
||||
if (SelectedProfileConfiguration != null)
|
||||
{
|
||||
SelectedProfileConfiguration.IsBeingEdited = true;
|
||||
_moduleService.SetActivationOverride(SelectedProfileConfiguration.Module);
|
||||
_profileService.ActivateProfile(SelectedProfileConfiguration);
|
||||
_profileService.RenderForEditor = true;
|
||||
|
||||
if (SelectedProfileConfiguration.Profile?.LastSelectedProfileElement is RenderProfileElement renderProfileElement)
|
||||
ChangeSelectedProfileElement(renderProfileElement);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -179,6 +217,7 @@ namespace Artemis.UI.Shared.Services
|
||||
if (SelectedProfile == null)
|
||||
return;
|
||||
|
||||
SelectedProfile.LastSelectedProfileElement = SelectedProfileElement;
|
||||
_profileService.SaveProfile(SelectedProfile, true);
|
||||
OnSelectedProfileUpdated(new ProfileConfigurationEventArgs(SelectedProfileConfiguration));
|
||||
UpdateProfilePreview();
|
||||
@ -478,6 +517,7 @@ namespace Artemis.UI.Shared.Services
|
||||
public event EventHandler? SelectedDataBindingChanged;
|
||||
public event EventHandler? CurrentTimeChanged;
|
||||
public event EventHandler? PixelsPerSecondChanged;
|
||||
public event EventHandler? SuspendEditingChanged;
|
||||
public event EventHandler? ProfilePreviewUpdated;
|
||||
|
||||
protected virtual void OnSelectedProfileChanged(ProfileConfigurationEventArgs e)
|
||||
@ -510,6 +550,11 @@ namespace Artemis.UI.Shared.Services
|
||||
PixelsPerSecondChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
protected virtual void OnSuspendEditingChanged()
|
||||
{
|
||||
SuspendEditingChanged?.Invoke(this, EventArgs.Empty);
|
||||
}
|
||||
|
||||
protected virtual void OnProfilePreviewUpdated()
|
||||
{
|
||||
ProfilePreviewUpdated?.Invoke(this, EventArgs.Empty);
|
||||
|
||||
@ -27,6 +27,7 @@ namespace Artemis.UI
|
||||
{
|
||||
private ApplicationStateManager _applicationStateManager;
|
||||
private ICoreService _core;
|
||||
private ILogger _exceptionLogger;
|
||||
|
||||
public Bootstrapper()
|
||||
{
|
||||
@ -48,11 +49,11 @@ namespace Artemis.UI
|
||||
{
|
||||
_applicationStateManager = new ApplicationStateManager(Kernel, Args);
|
||||
Core.Utilities.PrepareFirstLaunch();
|
||||
|
||||
ILogger logger = Kernel.Get<ILogger>();
|
||||
|
||||
_exceptionLogger = Kernel.Get<ILogger>();
|
||||
if (_applicationStateManager.FocusExistingInstance())
|
||||
{
|
||||
logger.Information("Shutting down because a different instance is already running.");
|
||||
_exceptionLogger.Information("Shutting down because a different instance is already running.");
|
||||
Application.Current.Shutdown(1);
|
||||
return;
|
||||
}
|
||||
@ -63,7 +64,7 @@ namespace Artemis.UI
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
logger.Error($"Failed to set DPI-Awareness: {ex.Message}");
|
||||
_exceptionLogger.Error($"Failed to set DPI-Awareness: {ex.Message}");
|
||||
}
|
||||
|
||||
IViewManager viewManager = Kernel.Get<IViewManager>();
|
||||
@ -76,7 +77,7 @@ namespace Artemis.UI
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
HandleFatalException(e, logger);
|
||||
HandleFatalException(e);
|
||||
throw;
|
||||
}
|
||||
|
||||
@ -101,7 +102,7 @@ namespace Artemis.UI
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
HandleFatalException(e, logger);
|
||||
HandleFatalException(e);
|
||||
throw;
|
||||
}
|
||||
});
|
||||
@ -132,12 +133,11 @@ namespace Artemis.UI
|
||||
|
||||
protected override void OnUnhandledException(DispatcherUnhandledExceptionEventArgs e)
|
||||
{
|
||||
ILogger logger = Kernel.Get<ILogger>();
|
||||
logger.Fatal(e.Exception, "Unhandled exception");
|
||||
|
||||
IDialogService dialogService = Kernel.Get<IDialogService>();
|
||||
try
|
||||
{
|
||||
_exceptionLogger.Fatal(e.Exception, "Unhandled exception");
|
||||
|
||||
IDialogService dialogService = Kernel.Get<IDialogService>();
|
||||
dialogService.ShowExceptionDialog("Artemis encountered an error", e.Exception);
|
||||
}
|
||||
catch (Exception)
|
||||
@ -149,9 +149,9 @@ namespace Artemis.UI
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
private void HandleFatalException(Exception e, ILogger logger)
|
||||
private void HandleFatalException(Exception e)
|
||||
{
|
||||
logger.Fatal(e, "Fatal exception during initialization, shutting down.");
|
||||
_exceptionLogger.Fatal(e, "Fatal exception during initialization, shutting down.");
|
||||
Execute.OnUIThread(() =>
|
||||
{
|
||||
_applicationStateManager.DisplayException(e);
|
||||
|
||||
29
src/Artemis.UI/Converters/LedIdToStringConverter.cs
Normal file
29
src/Artemis.UI/Converters/LedIdToStringConverter.cs
Normal file
@ -0,0 +1,29 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Windows.Data;
|
||||
using RGB.NET.Core;
|
||||
|
||||
namespace Artemis.UI.Converters
|
||||
{
|
||||
[ValueConversion(typeof(LedId), typeof(string))]
|
||||
public class LedIdToStringConverter : IValueConverter
|
||||
{
|
||||
#region Implementation of IValueConverter
|
||||
|
||||
/// <inheritdoc />
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
return value?.ToString();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
if (Enum.TryParse(typeof(LedId), value?.ToString(), true, out object parsedLedId))
|
||||
return parsedLedId;
|
||||
return LedId.Unknown1;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -5,6 +5,7 @@ using System.Windows.Data;
|
||||
|
||||
namespace Artemis.UI.Converters
|
||||
{
|
||||
[ValueConversion(typeof(Uri), typeof(string))]
|
||||
public class UriToFileNameConverter : IValueConverter
|
||||
{
|
||||
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
|
||||
|
||||
@ -1,4 +1,6 @@
|
||||
namespace Artemis.UI.Events
|
||||
using Artemis.UI.Screens.Sidebar;
|
||||
|
||||
namespace Artemis.UI.Events
|
||||
{
|
||||
public class RequestSelectSidebarItemEvent
|
||||
{
|
||||
@ -7,6 +9,12 @@
|
||||
DisplayName = displayName;
|
||||
}
|
||||
|
||||
public RequestSelectSidebarItemEvent(SidebarScreenViewModel viewModel)
|
||||
{
|
||||
ViewModel = viewModel;
|
||||
}
|
||||
|
||||
public string DisplayName { get; }
|
||||
public SidebarScreenViewModel ViewModel { get; }
|
||||
}
|
||||
}
|
||||
@ -77,7 +77,7 @@
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="1.5*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
|
||||
<!-- Left side -->
|
||||
<Grid Grid.Column="0">
|
||||
<Grid.RowDefinitions>
|
||||
@ -444,6 +444,28 @@
|
||||
Width="319" />
|
||||
|
||||
</Grid>
|
||||
|
||||
<!-- Suspended overlay -->
|
||||
<Border Grid.Row="0"
|
||||
Grid.Column="0"
|
||||
Grid.ColumnSpan="3"
|
||||
Grid.RowSpan="2"
|
||||
Panel.ZIndex="3"
|
||||
Background="#CD353535"
|
||||
Visibility="{Binding SuspendedEditing, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}">
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Center" Margin="16">
|
||||
<materialDesign:PackIcon Kind="TimerOffOutline" Width="150" Height="150" HorizontalAlignment="Center" />
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline4TextBlock}" TextWrapping="Wrap" HorizontalAlignment="Center" Margin="0 10">
|
||||
Timeline suspended
|
||||
</TextBlock>
|
||||
<TextBlock Style="{StaticResource MaterialDesignBody1TextBlock}" TextWrapping="Wrap" HorizontalAlignment="Center" TextAlignment="Center">
|
||||
The profile is currently running in normal mode and the timeline cannot be edited.
|
||||
</TextBlock>
|
||||
<TextBlock Style="{StaticResource MaterialDesignBody2TextBlock}" TextWrapping="Wrap" HorizontalAlignment="Center" TextAlignment="Center">
|
||||
Press <Run Text="F5" FontWeight="Bold"/> to switch between editor mode and normal mode. Auto-switching can be disabled in the options menu.
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
</Grid>
|
||||
</materialDesign:DialogHost>
|
||||
</UserControl>
|
||||
@ -122,6 +122,8 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
||||
set => ProfileEditorService.CurrentTime = TimeSpan.FromSeconds(value / ProfileEditorService.PixelsPerSecond);
|
||||
}
|
||||
|
||||
public bool SuspendedEditing => ProfileEditorService.SuspendEditing;
|
||||
|
||||
public int PropertyTreeIndex
|
||||
{
|
||||
get => _propertyTreeIndex;
|
||||
@ -190,6 +192,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
||||
|
||||
ProfileEditorService.SelectedProfileElementChanged += SelectedProfileEditorServiceOnSelectedProfileElementChanged;
|
||||
ProfileEditorService.CurrentTimeChanged += ProfileEditorServiceOnCurrentTimeChanged;
|
||||
ProfileEditorService.SuspendEditingChanged += ProfileEditorServiceOnSuspendEditingChanged;
|
||||
ProfileEditorService.SelectedDataBindingChanged += ProfileEditorServiceOnSelectedDataBindingChanged;
|
||||
ProfileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||
|
||||
@ -200,6 +203,7 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
||||
{
|
||||
ProfileEditorService.SelectedProfileElementChanged -= SelectedProfileEditorServiceOnSelectedProfileElementChanged;
|
||||
ProfileEditorService.CurrentTimeChanged -= ProfileEditorServiceOnCurrentTimeChanged;
|
||||
ProfileEditorService.SuspendEditingChanged -= ProfileEditorServiceOnSuspendEditingChanged;
|
||||
ProfileEditorService.SelectedDataBindingChanged -= ProfileEditorServiceOnSelectedDataBindingChanged;
|
||||
ProfileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
|
||||
|
||||
@ -230,6 +234,11 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
||||
NotifyOfPropertyChange(nameof(TimeCaretPosition));
|
||||
}
|
||||
|
||||
private void ProfileEditorServiceOnSuspendEditingChanged(object? sender, EventArgs e)
|
||||
{
|
||||
NotifyOfPropertyChange(nameof(SuspendedEditing));
|
||||
}
|
||||
|
||||
private void ProfileEditorServiceOnPixelsPerSecondChanged(object sender, EventArgs e)
|
||||
{
|
||||
NotifyOfPropertyChange(nameof(TimeCaretPosition));
|
||||
@ -559,6 +568,12 @@ namespace Artemis.UI.Screens.ProfileEditor.LayerProperties
|
||||
|
||||
private void CoreServiceOnFrameRendering(object sender, FrameRenderingEventArgs e)
|
||||
{
|
||||
if (!ProfileEditorService.Playing)
|
||||
{
|
||||
CoreService.FrameRendering -= CoreServiceOnFrameRendering;
|
||||
return;
|
||||
}
|
||||
|
||||
Execute.PostToUIThread(() =>
|
||||
{
|
||||
TimeSpan newTime = ProfileEditorService.CurrentTime.Add(TimeSpan.FromSeconds(e.DeltaTime));
|
||||
|
||||
@ -26,6 +26,8 @@
|
||||
<UserControl.InputBindings>
|
||||
<KeyBinding Command="{s:Action Undo}" Modifiers="Control" Key="Z" />
|
||||
<KeyBinding Command="{s:Action Redo}" Modifiers="Control" Key="Y" />
|
||||
<KeyBinding Command="{s:Action ToggleSuspend}" Key="F5" />
|
||||
<KeyBinding Command="{s:Action ToggleAutoSuspend}" Modifiers="Shift" Key="F5" />
|
||||
</UserControl.InputBindings>
|
||||
|
||||
<Grid ClipToBounds="True">
|
||||
@ -60,21 +62,24 @@
|
||||
s:View.ActionTarget="{Binding ProfileTreeViewModel}" />
|
||||
</MenuItem>
|
||||
<Separator />
|
||||
<MenuItem Header="View properties"
|
||||
<MenuItem Header="View Properties"
|
||||
Icon="{materialDesign:PackIcon Kind=Settings}"
|
||||
Command="{s:Action ViewProperties}"/>
|
||||
<MenuItem Header="Suspend profile"
|
||||
<MenuItem Header="Adapt Profile"
|
||||
Icon="{materialDesign:PackIcon Kind=Magic}"
|
||||
Command="{s:Action AdaptProfile}"/>
|
||||
<MenuItem Header="Suspend Profile"
|
||||
IsCheckable="True"
|
||||
IsChecked="{Binding ProfileConfiguration.IsSuspended}" />
|
||||
<Separator />
|
||||
<MenuItem Header="Export profile"
|
||||
<MenuItem Header="Export Profile"
|
||||
Icon="{materialDesign:PackIcon Kind=Export}"
|
||||
Command="{s:Action ExportProfile}" />
|
||||
<MenuItem Header="Duplicate profile"
|
||||
<MenuItem Header="Duplicate Profile"
|
||||
Icon="{materialDesign:PackIcon Kind=ContentDuplicate}"
|
||||
Command="{s:Action DuplicateProfile}" />
|
||||
<Separator />
|
||||
<MenuItem Header="Delete profile"
|
||||
<MenuItem Header="Delete Profile"
|
||||
Icon="{materialDesign:PackIcon Kind=Trash}"
|
||||
Command="{s:Action DeleteProfile}" />
|
||||
</MenuItem>
|
||||
@ -94,21 +99,47 @@
|
||||
Command="{s:Action Paste}"
|
||||
InputGestureText="Ctrl+V" />
|
||||
</MenuItem>
|
||||
<MenuItem Header="_Run">
|
||||
<MenuItem Header="_Switch run mode"
|
||||
Icon="{materialDesign:PackIcon Kind=SwapHorizontal}"
|
||||
Command="{s:Action ToggleSuspend}"
|
||||
InputGestureText="F5" />
|
||||
<MenuItem Header="Run Profile on Focus Loss"
|
||||
ToolTip="If enabled, run mode is set to normal on focus loss"
|
||||
IsCheckable="True"
|
||||
IsChecked="{Binding StopOnFocusLoss.Value}"
|
||||
InputGestureText="Shift+F5" />
|
||||
</MenuItem>
|
||||
<MenuItem Header="_Scripting" IsEnabled="False">
|
||||
<MenuItem Header="_Profile scripts"
|
||||
<MenuItem Header="_Profile Scripts"
|
||||
Icon="{materialDesign:PackIcon Kind=BookEdit}"
|
||||
Command="{s:Action OpenProfileScripts}"/>
|
||||
<MenuItem Header="_Layer scripts"
|
||||
<MenuItem Header="_Layer Scripts"
|
||||
Icon="{materialDesign:PackIcon Kind=Layers}"
|
||||
IsEnabled="{Binding HasSelectedElement}"
|
||||
Command="{s:Action OpenLayerScripts}"/>
|
||||
<MenuItem Header="_Property scripts"
|
||||
<MenuItem Header="_Property Scripts"
|
||||
Icon="{materialDesign:PackIcon Kind=FormTextbox}"
|
||||
IsEnabled="{Binding HasSelectedElement}"
|
||||
Command="{s:Action OpenLayerPropertyScripts}"/>
|
||||
</MenuItem>
|
||||
<MenuItem Header="_Options">
|
||||
<MenuItem Header="Focus Selected Layer"
|
||||
ToolTip="If enabled, displays only the layer you currently have selected"
|
||||
IsCheckable="True"
|
||||
IsChecked="{Binding FocusSelectedLayer.Value}"
|
||||
IsEnabled="False"/>
|
||||
<MenuItem Header="Display Data Model Values"
|
||||
IsCheckable="True"
|
||||
IsChecked="{Binding ShowDataModelValues.Value}"/>
|
||||
|
||||
<MenuItem Header="Apply All Data Bindings During Edit"
|
||||
ToolTip="If enabled, updates all data bindings instead of only the one you are editing"
|
||||
IsCheckable="True"
|
||||
IsChecked="{Binding AlwaysApplyDataBindings.Value}"/>
|
||||
</MenuItem>
|
||||
<MenuItem Header="_Help">
|
||||
<MenuItem Header="Artemis wiki"
|
||||
<MenuItem Header="Artemis Wiki"
|
||||
Icon="{materialDesign:PackIcon Kind=BookEdit}"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://wiki.artemis-rgb.com/" />
|
||||
@ -121,7 +152,7 @@
|
||||
Icon="{materialDesign:PackIcon Kind=Layers}"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://wiki.artemis-rgb.com/guides/user/profiles/layers" />
|
||||
<MenuItem Header="Display conditions"
|
||||
<MenuItem Header="Display Conditions"
|
||||
Icon="{materialDesign:PackIcon Kind=NotEqual}"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://wiki.artemis-rgb.com/guides/user/profiles/conditions" />
|
||||
@ -129,7 +160,7 @@
|
||||
Icon="{materialDesign:PackIcon Kind=Stopwatch}"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://wiki.artemis-rgb.com/guides/user/profiles/timeline" />
|
||||
<MenuItem Header="Data bindings"
|
||||
<MenuItem Header="Data Bindings"
|
||||
Icon="{materialDesign:PackIcon Kind=VectorLink}"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://wiki.artemis-rgb.com/guides/user/profiles/data-bindings" />
|
||||
@ -138,11 +169,11 @@
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://wiki.artemis-rgb.com/guides/user/profiles/scripting" />
|
||||
<Separator />
|
||||
<MenuItem Header="Report a bug"
|
||||
<MenuItem Header="Report a Bug"
|
||||
Icon="{materialDesign:PackIcon Kind=Github}"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://github.com/Artemis-RGB/Artemis/issues" />
|
||||
<MenuItem Header="Get help on Discord"
|
||||
<MenuItem Header="Get Help on Discord"
|
||||
Icon="{materialDesign:PackIcon Kind=Discord}"
|
||||
Command="{s:Action OpenUrl}"
|
||||
CommandParameter="https://discord.gg/S3MVaC9" />
|
||||
@ -152,7 +183,7 @@
|
||||
<Button Grid.Row="0"
|
||||
Grid.Column="2"
|
||||
Style="{StaticResource MaterialDesignIconForegroundButton}"
|
||||
ToolTip="Open debugger"
|
||||
ToolTip="Open Debugger"
|
||||
Margin="10 -4 10 0"
|
||||
Width="34"
|
||||
Height="34"
|
||||
|
||||
@ -1,24 +1,28 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Events;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Screens.ProfileEditor.DisplayConditions;
|
||||
using Artemis.UI.Screens.ProfileEditor.LayerProperties;
|
||||
using Artemis.UI.Screens.ProfileEditor.ProfileTree;
|
||||
using Artemis.UI.Screens.ProfileEditor.Visualization;
|
||||
using Artemis.UI.Screens.Sidebar;
|
||||
using Artemis.UI.Services;
|
||||
using Artemis.UI.Shared;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using Stylet;
|
||||
using ProfileConfigurationEventArgs = Artemis.UI.Shared.ProfileConfigurationEventArgs;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor
|
||||
{
|
||||
public class ProfileEditorViewModel : MainScreenViewModel
|
||||
public class ProfileEditorViewModel : MainScreenViewModel, IHandle<MainWindowFocusChangedEvent>
|
||||
{
|
||||
private readonly IDebugService _debugService;
|
||||
private readonly IMessageService _messageService;
|
||||
@ -28,14 +32,12 @@ namespace Artemis.UI.Screens.ProfileEditor
|
||||
private readonly ISettingsService _settingsService;
|
||||
private readonly ISidebarVmFactory _sidebarVmFactory;
|
||||
private readonly IWindowManager _windowManager;
|
||||
private PluginSetting<GridLength> _bottomPanelsHeight;
|
||||
private PluginSetting<GridLength> _dataModelConditionsHeight;
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private DisplayConditionsViewModel _displayConditionsViewModel;
|
||||
private PluginSetting<GridLength> _elementPropertiesWidth;
|
||||
private LayerPropertiesViewModel _layerPropertiesViewModel;
|
||||
private ProfileTreeViewModel _profileTreeViewModel;
|
||||
private ProfileViewModel _profileViewModel;
|
||||
private PluginSetting<GridLength> _sidePanelsWidth;
|
||||
private bool _suspendedManually;
|
||||
|
||||
public ProfileEditorViewModel(ProfileViewModel profileViewModel,
|
||||
ProfileTreeViewModel profileTreeViewModel,
|
||||
@ -48,6 +50,7 @@ namespace Artemis.UI.Screens.ProfileEditor
|
||||
IMessageService messageService,
|
||||
IDebugService debugService,
|
||||
IWindowManager windowManager,
|
||||
IEventAggregator eventAggregator,
|
||||
IScriptVmFactory scriptVmFactory,
|
||||
ISidebarVmFactory sidebarVmFactory)
|
||||
{
|
||||
@ -57,6 +60,7 @@ namespace Artemis.UI.Screens.ProfileEditor
|
||||
_messageService = messageService;
|
||||
_debugService = debugService;
|
||||
_windowManager = windowManager;
|
||||
_eventAggregator = eventAggregator;
|
||||
_scriptVmFactory = scriptVmFactory;
|
||||
_sidebarVmFactory = sidebarVmFactory;
|
||||
|
||||
@ -102,43 +106,20 @@ namespace Artemis.UI.Screens.ProfileEditor
|
||||
set => SetAndNotify(ref _profileViewModel, value);
|
||||
}
|
||||
|
||||
public PluginSetting<GridLength> SidePanelsWidth
|
||||
public bool SuspendedManually
|
||||
{
|
||||
get => _sidePanelsWidth;
|
||||
set => SetAndNotify(ref _sidePanelsWidth, value);
|
||||
get => _suspendedManually;
|
||||
set => SetAndNotify(ref _suspendedManually, value);
|
||||
}
|
||||
|
||||
public PluginSetting<GridLength> DataModelConditionsHeight
|
||||
{
|
||||
get => _dataModelConditionsHeight;
|
||||
set => SetAndNotify(ref _dataModelConditionsHeight, value);
|
||||
}
|
||||
|
||||
public PluginSetting<GridLength> BottomPanelsHeight
|
||||
{
|
||||
get => _bottomPanelsHeight;
|
||||
set => SetAndNotify(ref _bottomPanelsHeight, value);
|
||||
}
|
||||
|
||||
public PluginSetting<GridLength> ElementPropertiesWidth
|
||||
{
|
||||
get => _elementPropertiesWidth;
|
||||
set => SetAndNotify(ref _elementPropertiesWidth, value);
|
||||
}
|
||||
|
||||
public async Task AdaptActiveProfile()
|
||||
{
|
||||
if (_profileEditorService.SelectedProfileConfiguration?.Profile == null)
|
||||
return;
|
||||
|
||||
if (!await DialogService.ShowConfirmDialog(
|
||||
"Adapt profile",
|
||||
"Are you sure you want to adapt the profile to your current surface? Layer assignments may change."
|
||||
))
|
||||
return;
|
||||
|
||||
_profileService.AdaptProfile(_profileEditorService.SelectedProfileConfiguration.Profile);
|
||||
}
|
||||
public PluginSetting<GridLength> SidePanelsWidth => _settingsService.GetSetting("ProfileEditor.SidePanelsWidth", new GridLength(385));
|
||||
public PluginSetting<GridLength> DataModelConditionsHeight => _settingsService.GetSetting("ProfileEditor.DataModelConditionsHeight", new GridLength(345));
|
||||
public PluginSetting<GridLength> BottomPanelsHeight => _settingsService.GetSetting("ProfileEditor.BottomPanelsHeight", new GridLength(265));
|
||||
public PluginSetting<GridLength> ElementPropertiesWidth => _settingsService.GetSetting("ProfileEditor.ElementPropertiesWidth", new GridLength(545));
|
||||
public PluginSetting<bool> StopOnFocusLoss => _settingsService.GetSetting("ProfileEditor.StopOnFocusLoss", true);
|
||||
public PluginSetting<bool> ShowDataModelValues => _settingsService.GetSetting("ProfileEditor.ShowDataModelValues", false);
|
||||
public PluginSetting<bool> FocusSelectedLayer => _settingsService.GetSetting("ProfileEditor.FocusSelectedLayer", true);
|
||||
public PluginSetting<bool> AlwaysApplyDataBindings => _settingsService.GetSetting("ProfileEditor.AlwaysApplyDataBindings", true);
|
||||
|
||||
public void Undo()
|
||||
{
|
||||
@ -194,25 +175,52 @@ namespace Artemis.UI.Screens.ProfileEditor
|
||||
_messageService.ShowMessage("Redid profile update", "UNDO", Undo);
|
||||
}
|
||||
|
||||
public void ToggleSuspend()
|
||||
{
|
||||
_profileEditorService.SuspendEditing = !_profileEditorService.SuspendEditing;
|
||||
SuspendedManually = _profileEditorService.SuspendEditing;
|
||||
}
|
||||
|
||||
public void ToggleAutoSuspend()
|
||||
{
|
||||
StopOnFocusLoss.Value = !StopOnFocusLoss.Value;
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
StopOnFocusLoss.AutoSave = true;
|
||||
ShowDataModelValues.AutoSave = true;
|
||||
FocusSelectedLayer.AutoSave = true;
|
||||
AlwaysApplyDataBindings.AutoSave = true;
|
||||
|
||||
_profileEditorService.SelectedProfileChanged += ProfileEditorServiceOnSelectedProfileChanged;
|
||||
_profileEditorService.SelectedProfileElementChanged += ProfileEditorServiceOnSelectedProfileElementChanged;
|
||||
LoadWorkspaceSettings();
|
||||
_eventAggregator.Subscribe(this);
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
protected override void OnClose()
|
||||
{
|
||||
StopOnFocusLoss.AutoSave = false;
|
||||
ShowDataModelValues.AutoSave = false;
|
||||
FocusSelectedLayer.AutoSave = false;
|
||||
AlwaysApplyDataBindings.AutoSave = false;
|
||||
|
||||
_profileEditorService.SelectedProfileChanged -= ProfileEditorServiceOnSelectedProfileChanged;
|
||||
_profileEditorService.SelectedProfileElementChanged -= ProfileEditorServiceOnSelectedProfileElementChanged;
|
||||
_eventAggregator.Unsubscribe(this);
|
||||
SaveWorkspaceSettings();
|
||||
|
||||
_profileEditorService.SuspendEditing = false;
|
||||
_profileEditorService.ChangeSelectedProfileConfiguration(null);
|
||||
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void ProfileEditorServiceOnSelectedProfileChanged(object sender, ProfileConfigurationEventArgs e)
|
||||
{
|
||||
NotifyOfPropertyChange(nameof(ProfileConfiguration));
|
||||
@ -223,14 +231,6 @@ namespace Artemis.UI.Screens.ProfileEditor
|
||||
NotifyOfPropertyChange(nameof(HasSelectedElement));
|
||||
}
|
||||
|
||||
private void LoadWorkspaceSettings()
|
||||
{
|
||||
SidePanelsWidth = _settingsService.GetSetting("ProfileEditor.SidePanelsWidth", new GridLength(385));
|
||||
DataModelConditionsHeight = _settingsService.GetSetting("ProfileEditor.DataModelConditionsHeight", new GridLength(345));
|
||||
BottomPanelsHeight = _settingsService.GetSetting("ProfileEditor.BottomPanelsHeight", new GridLength(265));
|
||||
ElementPropertiesWidth = _settingsService.GetSetting("ProfileEditor.ElementPropertiesWidth", new GridLength(545));
|
||||
}
|
||||
|
||||
private void SaveWorkspaceSettings()
|
||||
{
|
||||
SidePanelsWidth.Save();
|
||||
@ -249,6 +249,20 @@ namespace Artemis.UI.Screens.ProfileEditor
|
||||
await _sidebarVmFactory.SidebarProfileConfigurationViewModel(_profileEditorService.SelectedProfileConfiguration).ViewProperties();
|
||||
}
|
||||
|
||||
public async Task AdaptProfile()
|
||||
{
|
||||
if (_profileEditorService.SelectedProfileConfiguration?.Profile == null)
|
||||
return;
|
||||
|
||||
if (!await DialogService.ShowConfirmDialog(
|
||||
"Adapt profile",
|
||||
"Are you sure you want to adapt the profile to your current surface? Layer assignments may change."
|
||||
))
|
||||
return;
|
||||
|
||||
_profileService.AdaptProfile(_profileEditorService.SelectedProfileConfiguration.Profile);
|
||||
}
|
||||
|
||||
public void DuplicateProfile()
|
||||
{
|
||||
ProfileConfigurationExportModel export = _profileService.ExportProfile(ProfileConfiguration);
|
||||
@ -322,5 +336,18 @@ namespace Artemis.UI.Screens.ProfileEditor
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Implementation of IHandle<in MainWindowFocusChangedEvent>
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Handle(MainWindowFocusChangedEvent message)
|
||||
{
|
||||
if (!StopOnFocusLoss.Value || SuspendedManually)
|
||||
return;
|
||||
|
||||
_profileEditorService.SuspendEditing = !message.IsFocused;
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -97,6 +97,11 @@
|
||||
<b:Interaction.Behaviors>
|
||||
<behaviors:TreeViewSelectionBehavior SelectedItem="{Binding SelectedTreeItem}" />
|
||||
</b:Interaction.Behaviors>
|
||||
<TreeView.ItemContainerStyle>
|
||||
<Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource MaterialDesignTreeViewItem}">
|
||||
<Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay, FallbackValue=False}"/>
|
||||
</Style>
|
||||
</TreeView.ItemContainerStyle>
|
||||
<TreeView.Resources>
|
||||
<HierarchicalDataTemplate DataType="{x:Type treeItem:FolderViewModel}" ItemsSource="{Binding Items}">
|
||||
<ContentControl s:View.Model="{Binding}" />
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
using Artemis.Core;
|
||||
@ -24,8 +25,6 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
|
||||
{
|
||||
_profileEditorService = profileEditorService;
|
||||
_profileTreeVmFactory = profileTreeVmFactory;
|
||||
|
||||
CreateRootFolderViewModel();
|
||||
}
|
||||
|
||||
public TreeItemViewModel SelectedTreeItem
|
||||
@ -33,7 +32,7 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
|
||||
get => _selectedTreeItem;
|
||||
set
|
||||
{
|
||||
if (!_updatingTree && SetAndNotify(ref _selectedTreeItem, value) && !_draggingTreeView)
|
||||
if (!_updatingTree && SetAndNotify(ref _selectedTreeItem, value) && !_draggingTreeView)
|
||||
ApplySelectedTreeItem();
|
||||
}
|
||||
}
|
||||
@ -54,6 +53,7 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
Subscribe();
|
||||
CreateRootFolderViewModel();
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
@ -83,6 +83,14 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree
|
||||
|
||||
ActiveItem = _profileTreeVmFactory.FolderViewModel(folder);
|
||||
_updatingTree = false;
|
||||
|
||||
Execute.PostToUIThread(async () =>
|
||||
{
|
||||
await Task.Delay(1500);
|
||||
if (ActiveItem != null)
|
||||
SelectedTreeItem = ActiveItem.GetAllChildren().FirstOrDefault(c => c.ProfileElement == _profileEditorService.SelectedProfileElement);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
#region IDropTarget
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using Artemis.Core;
|
||||
using System.ComponentModel;
|
||||
using Artemis.Core;
|
||||
using Artemis.Core.Services;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Shared.Services;
|
||||
@ -19,5 +20,35 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
|
||||
}
|
||||
|
||||
public override bool SupportsChildren => true;
|
||||
|
||||
public override bool IsExpanded
|
||||
{
|
||||
get => ((Folder) ProfileElement).IsExpanded;
|
||||
set => ((Folder) ProfileElement).IsExpanded = value;
|
||||
}
|
||||
|
||||
private void ProfileElementOnPropertyChanged(object sender, PropertyChangedEventArgs e)
|
||||
{
|
||||
if (e.PropertyName == nameof(Folder.IsExpanded))
|
||||
NotifyOfPropertyChange(nameof(IsExpanded));
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
ProfileElement.PropertyChanged += ProfileElementOnPropertyChanged;
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnClose()
|
||||
{
|
||||
ProfileElement.PropertyChanged -= ProfileElementOnPropertyChanged;
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -33,5 +33,7 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
|
||||
public Layer Layer => ProfileElement as Layer;
|
||||
public bool ShowIcons => Layer?.LayerBrush != null;
|
||||
public override bool SupportsChildren => false;
|
||||
|
||||
public override bool IsExpanded { get; set; }
|
||||
}
|
||||
}
|
||||
@ -52,6 +52,7 @@ namespace Artemis.UI.Screens.ProfileEditor.ProfileTree.TreeItem
|
||||
public bool CanPasteElement => _profileEditorService.GetCanPasteProfileElement();
|
||||
|
||||
public abstract bool SupportsChildren { get; }
|
||||
public abstract bool IsExpanded { get; set; }
|
||||
|
||||
public List<TreeItemViewModel> GetAllChildren()
|
||||
{
|
||||
|
||||
@ -0,0 +1,23 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.SuspendedProfileEditorView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.UI.Screens.ProfileEditor"
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<StackPanel HorizontalAlignment="Center" VerticalAlignment="Top" Margin="16">
|
||||
<materialDesign:PackIcon Kind="PauseCircle" Width="250" Height="250" HorizontalAlignment="Center" />
|
||||
<TextBlock Style="{StaticResource MaterialDesignHeadline4TextBlock}" TextWrapping="Wrap" HorizontalAlignment="Center" Margin="0 25">
|
||||
Profile editing has been paused
|
||||
</TextBlock>
|
||||
<TextBlock Style="{StaticResource MaterialDesignBody1TextBlock}" TextWrapping="Wrap" HorizontalAlignment="Center">
|
||||
Artemis has resumed regular profile playback. As soon as you focus this window, the editor will open to continue editing
|
||||
'<Run Text="{Binding PreviousSelectedProfileConfiguration.Name}" />'.
|
||||
</TextBlock>
|
||||
<TextBlock Style="{StaticResource MaterialDesignBody1TextBlock}" Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" HorizontalAlignment="Center">
|
||||
You can disable this behaviour in the editor's option menu.
|
||||
</TextBlock>
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@ -0,0 +1,53 @@
|
||||
using Artemis.Core;
|
||||
using Artemis.UI.Events;
|
||||
using Artemis.UI.Shared.Services;
|
||||
using Stylet;
|
||||
|
||||
namespace Artemis.UI.Screens.ProfileEditor
|
||||
{
|
||||
public class SuspendedProfileEditorViewModel : MainScreenViewModel, IHandle<MainWindowFocusChangedEvent>
|
||||
{
|
||||
private readonly IEventAggregator _eventAggregator;
|
||||
private readonly IProfileEditorService _profileEditorService;
|
||||
private ProfileConfiguration _previousSelectedProfileConfiguration;
|
||||
|
||||
public SuspendedProfileEditorViewModel(IEventAggregator eventAggregator, IProfileEditorService profileEditorService)
|
||||
{
|
||||
_eventAggregator = eventAggregator;
|
||||
_profileEditorService = profileEditorService;
|
||||
}
|
||||
|
||||
public ProfileConfiguration PreviousSelectedProfileConfiguration
|
||||
{
|
||||
get => _previousSelectedProfileConfiguration;
|
||||
set => SetAndNotify(ref _previousSelectedProfileConfiguration, value);
|
||||
}
|
||||
|
||||
public void Handle(MainWindowFocusChangedEvent message)
|
||||
{
|
||||
if (!message.IsFocused)
|
||||
return;
|
||||
|
||||
RootViewModel rootViewModel = (RootViewModel) Parent;
|
||||
if (PreviousSelectedProfileConfiguration != null)
|
||||
rootViewModel.SidebarViewModel.SelectProfileConfiguration(PreviousSelectedProfileConfiguration);
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
PreviousSelectedProfileConfiguration = _profileEditorService.PreviousSelectedProfileConfiguration;
|
||||
_eventAggregator.Subscribe(this);
|
||||
base.OnInitialActivate();
|
||||
}
|
||||
|
||||
protected override void OnClose()
|
||||
{
|
||||
_eventAggregator.Unsubscribe(this);
|
||||
base.OnClose();
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,4 @@
|
||||
<UserControl x:Class="Artemis.UI.Screens.ProfileEditor.Visualization.ProfileView"
|
||||
<UserControl
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
@ -7,9 +7,13 @@
|
||||
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
xmlns:visualization="clr-namespace:Artemis.UI.Screens.ProfileEditor.Visualization"
|
||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||
xmlns:Converters="clr-namespace:Artemis.UI.Converters" x:Class="Artemis.UI.Screens.ProfileEditor.Visualization.ProfileView"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="510.9" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance {x:Type visualization:ProfileViewModel}}">
|
||||
<UserControl.Resources>
|
||||
<Converters:InverseBooleanConverter x:Key="InverseBooleanConverter"/>
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
@ -27,13 +31,16 @@
|
||||
<ListBoxItem ToolTip="Pan over different parts of the surface - Ctrl">
|
||||
<materialDesign:PackIcon Kind="HandLeft" />
|
||||
</ListBoxItem>
|
||||
<ListBoxItem ToolTip="Transform layer shape (hold SHIFT for incremental changes and X/Y snapping) - Ctrl+T" IsEnabled="{Binding CanSelectEditTool}">
|
||||
<ListBoxItem ToolTip="Transform layer shape (hold SHIFT for incremental changes and X/Y snapping) - Ctrl+T"
|
||||
IsEnabled="{Binding CanSelectEditTool}">
|
||||
<materialDesign:PackIcon Kind="TransitConnectionVariant" />
|
||||
</ListBoxItem>
|
||||
<ListBoxItem ToolTip="Change layer selection (hold SHIFT to add to existing selection) - Ctrl+Q">
|
||||
<ListBoxItem ToolTip="Change layer selection (hold SHIFT to add to existing selection) - Ctrl+Q"
|
||||
IsEnabled="{Binding SuspendedEditing, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}">
|
||||
<materialDesign:PackIcon Kind="SelectionDrag" />
|
||||
</ListBoxItem>
|
||||
<ListBoxItem ToolTip="Remove from layer selection - Ctrl+W">
|
||||
<ListBoxItem ToolTip="Remove from layer selection - Ctrl+W"
|
||||
IsEnabled="{Binding SuspendedEditing, Converter={StaticResource InverseBooleanConverter}, Mode=OneWay}">
|
||||
<materialDesign:PackIcon Kind="SelectOff" />
|
||||
</ListBoxItem>
|
||||
</ListBox>
|
||||
@ -71,7 +78,7 @@
|
||||
</VisualBrush>
|
||||
</Grid.Background>
|
||||
|
||||
<Grid Name="DeviceDisplayGrid">
|
||||
<Grid x:Name="DeviceDisplayGrid">
|
||||
<Grid.RenderTransform>
|
||||
<TransformGroup>
|
||||
<ScaleTransform ScaleX="{Binding PanZoomViewModel.Zoom}" ScaleY="{Binding PanZoomViewModel.Zoom}" />
|
||||
@ -85,7 +92,7 @@
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemContainerStyle>
|
||||
<Style TargetType="ContentPresenter">
|
||||
<Style TargetType="{x:Type ContentPresenter}">
|
||||
<Setter Property="Canvas.Left" Value="{Binding X}" />
|
||||
<Setter Property="Canvas.Top" Value="{Binding Y}" />
|
||||
</Style>
|
||||
@ -94,13 +101,15 @@
|
||||
<DataTemplate>
|
||||
<shared:DeviceVisualizer Device="{Binding}"
|
||||
ShowColors="True"
|
||||
HighlightedLeds="{Binding DataContext.HighlightedLeds, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Mode=OneWay}" />
|
||||
RenderOptions.BitmapScalingMode="HighQuality"
|
||||
HighlightedLeds="{Binding DataContext.HighlightedLeds, Mode=OneWay, RelativeSource={RelativeSource AncestorType={x:Type UserControl}}}" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
|
||||
<Grid Name="EditorDisplayGrid"
|
||||
<Grid x:Name="EditorDisplayGrid"
|
||||
Visibility="{Binding SuspendedEditing, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}"
|
||||
shared:SizeObserver.Observe="True"
|
||||
shared:SizeObserver.ObservedHeight="{Binding PanZoomViewModel.CanvasHeight}"
|
||||
shared:SizeObserver.ObservedWidth="{Binding PanZoomViewModel.CanvasWidth}">
|
||||
@ -117,7 +126,7 @@
|
||||
</ItemsPanelTemplate>
|
||||
</ItemsControl.ItemsPanel>
|
||||
<ItemsControl.ItemContainerStyle>
|
||||
<Style TargetType="ContentPresenter">
|
||||
<Style TargetType="{x:Type ContentPresenter}">
|
||||
<Setter Property="Canvas.Left" Value="{Binding X}" />
|
||||
<Setter Property="Canvas.Top" Value="{Binding Y}" />
|
||||
</Style>
|
||||
@ -130,26 +139,8 @@
|
||||
</ItemsControl>
|
||||
</Grid>
|
||||
|
||||
<StackPanel ZIndex="1" VerticalAlignment="Bottom" HorizontalAlignment="Left" Margin="10" Cursor="Arrow">
|
||||
<materialDesign:Card Padding="8">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<CheckBox Style="{StaticResource MaterialDesignCheckBox}"
|
||||
IsChecked="{Binding FocusSelectedLayer.Value}"
|
||||
ToolTip="If selected, dims all LEDs that are not part of the selected layer">
|
||||
Focus selected layer
|
||||
</CheckBox>
|
||||
<CheckBox Style="{StaticResource MaterialDesignCheckBox}"
|
||||
Margin="10 0 0 0"
|
||||
IsChecked="{Binding AlwaysApplyDataBindings.Value}"
|
||||
ToolTip="If selected, updates all data bindings instead of only the one you are editing">
|
||||
Apply all data bindings in editor
|
||||
</CheckBox>
|
||||
</StackPanel>
|
||||
</materialDesign:Card>
|
||||
</StackPanel>
|
||||
|
||||
<StackPanel Orientation="Vertical" VerticalAlignment="Bottom" HorizontalAlignment="Right"
|
||||
Margin="10" ZIndex="1">
|
||||
Margin="10" Panel.ZIndex="1">
|
||||
<Slider Orientation="Vertical"
|
||||
HorizontalAlignment="Center"
|
||||
Margin="0 10"
|
||||
|
||||
@ -26,12 +26,10 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
|
||||
private int _activeToolIndex;
|
||||
private VisualizationToolViewModel _activeToolViewModel;
|
||||
private PluginSetting<bool> _alwaysApplyDataBindings;
|
||||
private bool _canApplyToLayer;
|
||||
private bool _canSelectEditTool;
|
||||
private BindableCollection<ArtemisDevice> _devices;
|
||||
private BindableCollection<ArtemisLed> _highlightedLeds;
|
||||
private PluginSetting<bool> _focusSelectedLayer;
|
||||
private DateTime _lastUpdate;
|
||||
private PanZoomViewModel _panZoomViewModel;
|
||||
private Layer _previousSelectedLayer;
|
||||
@ -79,18 +77,6 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
set => SetAndNotify(ref _highlightedLeds, value);
|
||||
}
|
||||
|
||||
public PluginSetting<bool> AlwaysApplyDataBindings
|
||||
{
|
||||
get => _alwaysApplyDataBindings;
|
||||
set => SetAndNotify(ref _alwaysApplyDataBindings, value);
|
||||
}
|
||||
|
||||
public PluginSetting<bool> FocusSelectedLayer
|
||||
{
|
||||
get => _focusSelectedLayer;
|
||||
set => SetAndNotify(ref _focusSelectedLayer, value);
|
||||
}
|
||||
|
||||
public VisualizationToolViewModel ActiveToolViewModel
|
||||
{
|
||||
get => _activeToolViewModel;
|
||||
@ -132,9 +118,17 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
set => SetAndNotify(ref _canApplyToLayer, value);
|
||||
}
|
||||
|
||||
public bool SuspendedEditing => _profileEditorService.SuspendEditing;
|
||||
|
||||
protected override void OnInitialActivate()
|
||||
{
|
||||
PanZoomViewModel = new PanZoomViewModel {LimitToZero = false};
|
||||
PanZoomViewModel = new PanZoomViewModel
|
||||
{
|
||||
LimitToZero = false,
|
||||
PanX = _settingsService.GetSetting("ProfileEditor.PanX", 0d).Value,
|
||||
PanY = _settingsService.GetSetting("ProfileEditor.PanY", 0d).Value,
|
||||
Zoom = _settingsService.GetSetting("ProfileEditor.Zoom", 0d).Value
|
||||
};
|
||||
|
||||
Devices = new BindableCollection<ArtemisDevice>();
|
||||
HighlightedLeds = new BindableCollection<ArtemisLed>();
|
||||
@ -144,15 +138,12 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
|
||||
ApplyActiveProfile();
|
||||
|
||||
AlwaysApplyDataBindings = _settingsService.GetSetting("ProfileEditor.AlwaysApplyDataBindings", true);
|
||||
FocusSelectedLayer = _settingsService.GetSetting("ProfileEditor.FocusSelectedLayer", true);
|
||||
|
||||
_lastUpdate = DateTime.Now;
|
||||
_coreService.FrameRendered += OnFrameRendered;
|
||||
|
||||
FocusSelectedLayer.SettingChanged += HighlightSelectedLayerOnSettingChanged;
|
||||
_rgbService.DeviceAdded += RgbServiceOnDevicesModified;
|
||||
_rgbService.DeviceRemoved += RgbServiceOnDevicesModified;
|
||||
_profileEditorService.SuspendEditingChanged += ProfileEditorServiceOnSuspendEditingChanged;
|
||||
_profileEditorService.SelectedProfileChanged += OnSelectedProfileChanged;
|
||||
_profileEditorService.SelectedProfileElementChanged += OnSelectedProfileElementChanged;
|
||||
_profileEditorService.SelectedProfileElementSaved += OnSelectedProfileElementSaved;
|
||||
@ -163,17 +154,21 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
protected override void OnClose()
|
||||
{
|
||||
_coreService.FrameRendered -= OnFrameRendered;
|
||||
FocusSelectedLayer.SettingChanged -= HighlightSelectedLayerOnSettingChanged;
|
||||
_rgbService.DeviceAdded -= RgbServiceOnDevicesModified;
|
||||
_rgbService.DeviceRemoved -= RgbServiceOnDevicesModified;
|
||||
_profileEditorService.SuspendEditingChanged -= ProfileEditorServiceOnSuspendEditingChanged;
|
||||
_profileEditorService.SelectedProfileChanged -= OnSelectedProfileChanged;
|
||||
_profileEditorService.SelectedProfileElementChanged -= OnSelectedProfileElementChanged;
|
||||
_profileEditorService.SelectedProfileElementSaved -= OnSelectedProfileElementSaved;
|
||||
if (_previousSelectedLayer != null)
|
||||
_previousSelectedLayer.LayerBrushUpdated -= SelectedLayerOnLayerBrushUpdated;
|
||||
|
||||
AlwaysApplyDataBindings.Save();
|
||||
FocusSelectedLayer.Save();
|
||||
_settingsService.GetSetting("ProfileEditor.PanX", 0d).Value = PanZoomViewModel.PanX;
|
||||
_settingsService.GetSetting("ProfileEditor.PanX", 0d).Save();
|
||||
_settingsService.GetSetting("ProfileEditor.PanY", 0d).Value = PanZoomViewModel.PanY;
|
||||
_settingsService.GetSetting("ProfileEditor.PanY", 0d).Save();
|
||||
_settingsService.GetSetting("ProfileEditor.Zoom", 0d).Value = PanZoomViewModel.Zoom;
|
||||
_settingsService.GetSetting("ProfileEditor.Zoom", 0d).Save();
|
||||
|
||||
base.OnClose();
|
||||
}
|
||||
@ -210,12 +205,19 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
private void UpdateLedsDimStatus()
|
||||
{
|
||||
HighlightedLeds.Clear();
|
||||
if (FocusSelectedLayer.Value && _profileEditorService.SelectedProfileElement is Layer layer)
|
||||
if (_profileEditorService.SelectedProfileElement is Layer layer)
|
||||
HighlightedLeds.AddRange(layer.Leds);
|
||||
}
|
||||
|
||||
private void UpdateCanSelectEditTool()
|
||||
{
|
||||
if (SuspendedEditing)
|
||||
{
|
||||
CanApplyToLayer = false;
|
||||
CanSelectEditTool = false;
|
||||
return;
|
||||
}
|
||||
|
||||
if (_profileEditorService.SelectedProfileElement is Layer layer)
|
||||
{
|
||||
CanApplyToLayer = true;
|
||||
@ -230,14 +232,14 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
if (CanSelectEditTool == false && ActiveToolIndex == 1)
|
||||
ActivateToolByIndex(2);
|
||||
}
|
||||
|
||||
|
||||
#region Buttons
|
||||
|
||||
private void ActivateToolByIndex(int value)
|
||||
{
|
||||
if (value == 1 && !CanSelectEditTool)
|
||||
return;
|
||||
|
||||
|
||||
switch (value)
|
||||
{
|
||||
case 0:
|
||||
@ -308,7 +310,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
TimeSpan delta = DateTime.Now - _lastUpdate;
|
||||
_lastUpdate = DateTime.Now;
|
||||
|
||||
if (!AlwaysApplyDataBindings.Value || _profileEditorService.SelectedProfile == null)
|
||||
if (SuspendedEditing || !_settingsService.GetSetting("ProfileEditor.AlwaysApplyDataBindings", true).Value || _profileEditorService.SelectedProfile == null)
|
||||
return;
|
||||
|
||||
foreach (IDataBindingRegistration dataBindingRegistration in _profileEditorService.SelectedProfile.GetAllFolders()
|
||||
@ -389,6 +391,12 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization
|
||||
ActivateToolByIndex(2);
|
||||
}
|
||||
|
||||
private void ProfileEditorServiceOnSuspendEditingChanged(object? sender, EventArgs e)
|
||||
{
|
||||
NotifyOfPropertyChange(nameof(SuspendedEditing));
|
||||
UpdateCanSelectEditTool();
|
||||
}
|
||||
|
||||
public void Handle(MainWindowKeyEvent message)
|
||||
{
|
||||
if (message.KeyDown)
|
||||
|
||||
@ -32,6 +32,9 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
|
||||
{
|
||||
base.MouseUp(sender, e);
|
||||
|
||||
if (ProfileEditorService.SuspendEditing)
|
||||
return;
|
||||
|
||||
Point position = PanZoomViewModel.GetRelativeMousePosition(sender, e);
|
||||
Rect selectedRect = new(MouseDownStartPosition, position);
|
||||
|
||||
|
||||
@ -37,6 +37,9 @@ namespace Artemis.UI.Screens.ProfileEditor.Visualization.Tools
|
||||
{
|
||||
base.MouseUp(sender, e);
|
||||
|
||||
if (ProfileEditorService.SuspendEditing)
|
||||
return;
|
||||
|
||||
Point position = PanZoomViewModel.GetRelativeMousePosition(sender, e);
|
||||
Rect selectedRect = new(MouseDownStartPosition, position);
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@
|
||||
UseLayoutRounding="True"
|
||||
Deactivated="{s:Action WindowDeactivated}"
|
||||
Activated="{s:Action WindowActivated}"
|
||||
StateChanged="{s:Action WindowStateChanged}"
|
||||
KeyDown="{s:Action WindowKeyDown}"
|
||||
KeyUp="{s:Action WindowKeyUp}"
|
||||
MouseDown="{s:Action WindowMouseDown}"
|
||||
|
||||
@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Input;
|
||||
@ -15,6 +16,7 @@ using MaterialDesignExtensions.Controls;
|
||||
using MaterialDesignThemes.Wpf;
|
||||
using Ninject;
|
||||
using Stylet;
|
||||
using Stylet.Xaml;
|
||||
using Constants = Artemis.Core.Constants;
|
||||
|
||||
namespace Artemis.UI.Screens
|
||||
@ -78,8 +80,7 @@ namespace Artemis.UI.Screens
|
||||
|
||||
public void WindowDeactivated()
|
||||
{
|
||||
WindowState windowState = ((Window) View).WindowState;
|
||||
if (windowState == WindowState.Minimized)
|
||||
if (_lostFocus)
|
||||
return;
|
||||
|
||||
_lostFocus = true;
|
||||
@ -95,6 +96,25 @@ namespace Artemis.UI.Screens
|
||||
_eventAggregator.Publish(new MainWindowFocusChangedEvent(true));
|
||||
}
|
||||
|
||||
// This is required because Windows incorrectly tells the window it is activated when minimizing using the taskbar
|
||||
public void WindowStateChanged()
|
||||
{
|
||||
if (((Window) View).WindowState == WindowState.Minimized)
|
||||
WindowDeactivated();
|
||||
else
|
||||
WindowActivated();
|
||||
}
|
||||
|
||||
#region Overrides of Screen
|
||||
|
||||
/// <inheritdoc />
|
||||
protected override void OnStateChanged(ScreenState previousState, ScreenState newState)
|
||||
{
|
||||
base.OnStateChanged(previousState, newState);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public void WindowKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
_eventAggregator.Publish(new MainWindowKeyEvent(sender, true, e));
|
||||
|
||||
@ -12,6 +12,7 @@
|
||||
d:DataContext="{d:DesignInstance {x:Type tabs:DeviceLedsTabViewModel}}">
|
||||
<UserControl.Resources>
|
||||
<converters:UriToFileNameConverter x:Key="UriToFileNameConverter" />
|
||||
<converters:LedIdToStringConverter x:Key="LedIdToStringConverter" />
|
||||
</UserControl.Resources>
|
||||
<Grid>
|
||||
<DataGrid ItemsSource="{Binding LedViewModels}"
|
||||
@ -31,7 +32,7 @@
|
||||
</Style>
|
||||
</DataGrid.Resources>
|
||||
<DataGrid.Columns>
|
||||
<materialDesign:DataGridTextColumn Binding="{Binding ArtemisLed.RgbLed.Id}" Header="LED ID" Width="Auto" />
|
||||
<materialDesign:DataGridTextColumn Binding="{Binding ArtemisLed.RgbLed.Id, Converter={StaticResource LedIdToStringConverter}, Mode=OneWay}" Header="LED ID" Width="Auto" />
|
||||
<materialDesign:DataGridTextColumn Binding="{Binding ArtemisLed.RgbLed.Color}" Header="Color (ARGB)" Width="Auto" CanUserSort="False" />
|
||||
<materialDesign:DataGridTextColumn Binding="{Binding ArtemisLed.Layout.Image, Converter={StaticResource UriToFileNameConverter}, Mode=OneWay}" Header="Image file" CanUserSort="False" />
|
||||
<materialDesign:DataGridTextColumn Binding="{Binding ArtemisLed.RgbLed.Shape}" Header="Shape" />
|
||||
|
||||
@ -126,7 +126,12 @@ namespace Artemis.UI.Screens.Sidebar
|
||||
|
||||
public void Handle(RequestSelectSidebarItemEvent message)
|
||||
{
|
||||
SidebarScreenViewModel requested = SidebarScreens.FirstOrDefault(s => s.DisplayName == message.DisplayName);
|
||||
SidebarScreenViewModel requested = null;
|
||||
if (message.DisplayName != null)
|
||||
requested = SidebarScreens.FirstOrDefault(s => s.DisplayName == message.DisplayName);
|
||||
else
|
||||
requested = message.ViewModel;
|
||||
|
||||
if (requested != null)
|
||||
SelectedSidebarScreen = requested;
|
||||
}
|
||||
@ -148,6 +153,8 @@ namespace Artemis.UI.Screens.Sidebar
|
||||
foreach (SidebarCategoryViewModel sidebarCategoryViewModel in Items)
|
||||
sidebarCategoryViewModel.SelectedProfileConfiguration = sidebarCategoryViewModel.Items.FirstOrDefault(i => i.ProfileConfiguration == profileConfiguration);
|
||||
|
||||
if (_profileEditorService.SuspendEditing)
|
||||
_profileEditorService.SuspendEditing = false;
|
||||
_profileEditorService.ChangeSelectedProfileConfiguration(profileConfiguration);
|
||||
if (profileConfiguration != null)
|
||||
{
|
||||
|
||||
@ -33,7 +33,11 @@
|
||||
Visibility="{Binding Device.Layout.Image, ConverterParameter=Inverted, Converter={StaticResource NullToVisibilityConverter}}"
|
||||
IsHitTestVisible="False"/>
|
||||
|
||||
<shared:DeviceVisualizer Device="{Binding Device}" ShowColors="True" VerticalAlignment="Top" HorizontalAlignment="Left" />
|
||||
<shared:DeviceVisualizer Device="{Binding Device}"
|
||||
RenderOptions.BitmapScalingMode="HighQuality"
|
||||
ShowColors="True"
|
||||
VerticalAlignment="Top"
|
||||
HorizontalAlignment="Left" />
|
||||
|
||||
</Grid>
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user