diff --git a/src/Artemis.Core/Models/Profile/Profile.cs b/src/Artemis.Core/Models/Profile/Profile.cs
index 5534e686d..7bbde4bd3 100644
--- a/src/Artemis.Core/Models/Profile/Profile.cs
+++ b/src/Artemis.Core/Models/Profile/Profile.cs
@@ -8,6 +8,15 @@ using SkiaSharp;
namespace Artemis.Core;
+
+internal enum FadingStatus
+{
+ Enabled,
+ FadingIn,
+ FadingOut,
+ Disabled
+}
+
///
/// Represents a profile containing folders and layers
///
@@ -18,12 +27,15 @@ public sealed class Profile : ProfileElement
private readonly ObservableCollection _scripts;
private bool _isFreshImport;
private ProfileElement? _lastSelectedProfileElement;
+ private double _opacity;
internal Profile(ProfileConfiguration configuration, ProfileEntity profileEntity) : base(null!)
{
_scripts = new ObservableCollection();
_scriptConfigurations = new ObservableCollection();
-
+ _opacity = 0d;
+
+ FadingStatus = FadingStatus.FadingIn;
Configuration = configuration;
Profile = this;
ProfileEntity = profileEntity;
@@ -81,6 +93,8 @@ public sealed class Profile : ProfileElement
internal List Exceptions { get; }
+ internal FadingStatus FadingStatus { get; private set; }
+
///
public override void Update(double deltaTime)
{
@@ -97,6 +111,16 @@ public sealed class Profile : ProfileElement
foreach (ProfileScript profileScript in Scripts)
profileScript.OnProfileUpdated(deltaTime);
+
+ const double OPACITY_PER_SECOND = 1;
+ if (FadingStatus == FadingStatus.FadingIn)
+ _opacity = Math.Clamp(_opacity + OPACITY_PER_SECOND * deltaTime, 0d, 1d);
+ if (FadingStatus == FadingStatus.FadingOut)
+ _opacity = Math.Clamp(_opacity - OPACITY_PER_SECOND * deltaTime, 0d, 1d);
+ if (_opacity == 0d)
+ FadingStatus = FadingStatus.Disabled;
+ if (_opacity == 1d)
+ FadingStatus = FadingStatus.Enabled;
}
}
@@ -111,9 +135,17 @@ public sealed class Profile : ProfileElement
foreach (ProfileScript profileScript in Scripts)
profileScript.OnProfileRendering(canvas, canvas.LocalClipBounds);
+ using var opacityPaint = new SKPaint();
+ if (Configuration.FadeInAndOut && FadingStatus != FadingStatus.Enabled)
+ opacityPaint.Color = new SKColor(0, 0, 0, (byte)(255d * Easings.CubicEaseInOut(_opacity)));
+
+ canvas.SaveLayer(opacityPaint);
+
foreach (ProfileElement profileElement in Children)
profileElement.Render(canvas, basePosition, editorFocus);
+ canvas.Restore();
+
foreach (ProfileScript profileScript in Scripts)
profileScript.OnProfileRendered(canvas, canvas.LocalClipBounds);
@@ -165,6 +197,17 @@ public sealed class Profile : ProfileElement
layer.PopulateLeds(devices);
}
+ ///
+ /// Starts the fade out process.
+ ///
+ public void FadeOut()
+ {
+ if (Disposed)
+ throw new ObjectDisposedException("Profile");
+
+ FadingStatus = FadingStatus.FadingOut;
+ }
+
#region Overrides of BreakableModel
///
diff --git a/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfiguration.cs b/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfiguration.cs
index 3390a2863..b349acfd1 100644
--- a/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfiguration.cs
+++ b/src/Artemis.Core/Models/ProfileConfiguration/ProfileConfiguration.cs
@@ -21,6 +21,7 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable
private bool _isBeingEdited;
private bool _isMissingModule;
private bool _isSuspended;
+ private bool _fadeInAndOut;
private Module? _module;
private string _name;
@@ -160,6 +161,15 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable
internal set => SetAndNotify(ref _profile, value);
}
+ ///
+ /// Gets or sets a boolean indicating whether this profile should fade in and out when enabling or disabling
+ ///
+ public bool FadeInAndOut
+ {
+ get => _fadeInAndOut;
+ set => SetAndNotify(ref _fadeInAndOut, value);
+ }
+
///
/// Gets or sets the module this profile uses
///
@@ -272,6 +282,7 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable
IsSuspended = Entity.IsSuspended;
ActivationBehaviour = (ActivationBehaviour) Entity.ActivationBehaviour;
HotkeyMode = (ProfileConfigurationHotkeyMode) Entity.HotkeyMode;
+ FadeInAndOut = Entity.FadeInAndOut;
Order = Entity.Order;
Icon.Load();
@@ -294,6 +305,7 @@ public class ProfileConfiguration : BreakableModel, IStorageModel, IDisposable
Entity.ActivationBehaviour = (int) ActivationBehaviour;
Entity.HotkeyMode = (int) HotkeyMode;
Entity.ProfileCategoryId = Category.Entity.Id;
+ Entity.FadeInAndOut = FadeInAndOut;
Entity.Order = Order;
Icon.Save();
diff --git a/src/Artemis.Core/Services/Storage/ProfileService.cs b/src/Artemis.Core/Services/Storage/ProfileService.cs
index d5adc7d87..6a0c2ad52 100644
--- a/src/Artemis.Core/Services/Storage/ProfileService.cs
+++ b/src/Artemis.Core/Services/Storage/ProfileService.cs
@@ -214,7 +214,12 @@ internal class ProfileService : IProfileService
if (shouldBeActive && profileConfiguration.Profile == null && profileConfiguration.BrokenState != "Failed to activate profile")
profileConfiguration.TryOrBreak(() => ActivateProfile(profileConfiguration), "Failed to activate profile");
else if (!shouldBeActive && profileConfiguration.Profile != null)
- DeactivateProfile(profileConfiguration);
+ {
+ if (!profileConfiguration.FadeInAndOut || profileConfiguration.Profile.FadingStatus == FadingStatus.Disabled)
+ DeactivateProfile(profileConfiguration);
+ else if (profileConfiguration.Profile.FadingStatus == FadingStatus.Enabled)
+ RequestDeactivation(profileConfiguration);
+ }
profileConfiguration.Profile?.Update(deltaTime);
}
@@ -254,7 +259,7 @@ internal class ProfileService : IProfileService
{
ProfileConfiguration profileConfiguration = profileCategory.ProfileConfigurations[j];
// Ensure all criteria are met before rendering
- if (!profileConfiguration.IsSuspended && !profileConfiguration.IsMissingModule && profileConfiguration.ActivationConditionMet)
+ if (!profileConfiguration.IsSuspended && !profileConfiguration.IsMissingModule && (profileConfiguration.ActivationConditionMet || profileConfiguration.Profile?.FadingStatus == FadingStatus.FadingOut))
profileConfiguration.Profile?.Render(canvas, SKPointI.Empty, null);
}
catch (Exception e)
@@ -361,6 +366,16 @@ internal class ProfileService : IProfileService
OnProfileDeactivated(new ProfileConfigurationEventArgs(profileConfiguration));
}
+ public void RequestDeactivation(ProfileConfiguration profileConfiguration)
+ {
+ if (profileConfiguration.IsBeingEdited)
+ throw new ArtemisCoreException("Cannot disable a profile that is being edited, that's rude");
+ if (profileConfiguration.Profile == null)
+ return;
+
+ profileConfiguration.Profile.FadeOut();
+ }
+
public void DeleteProfile(ProfileConfiguration profileConfiguration)
{
DeactivateProfile(profileConfiguration);
diff --git a/src/Artemis.Storage/Entities/Profile/ProfileConfigurationEntity.cs b/src/Artemis.Storage/Entities/Profile/ProfileConfigurationEntity.cs
index 377d78ce7..e91ddcc96 100644
--- a/src/Artemis.Storage/Entities/Profile/ProfileConfigurationEntity.cs
+++ b/src/Artemis.Storage/Entities/Profile/ProfileConfigurationEntity.cs
@@ -25,4 +25,6 @@ public class ProfileConfigurationEntity
public Guid ProfileCategoryId { get; set; }
public Guid ProfileId { get; set; }
+
+ public bool FadeInAndOut { get; set; }
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditView.axaml b/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditView.axaml
index fed01edac..a127cdc14 100644
--- a/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditView.axaml
+++ b/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditView.axaml
@@ -127,6 +127,9 @@
+
+ Fade when enabling and disabling
+
diff --git a/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs b/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs
index ed55d14c3..fe773c4f5 100644
--- a/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs
+++ b/src/Artemis.UI/Screens/Sidebar/Dialogs/ProfileConfigurationEditViewModel.cs
@@ -30,6 +30,7 @@ public class ProfileConfigurationEditViewModel : DialogViewModelBase? _materialIcons;
@@ -57,6 +58,7 @@ public class ProfileConfigurationEditViewModel : DialogViewModelBase RaiseAndSetIfChanged(ref _disableHotkey, value);
}
+ public bool FadeInAndOut
+ {
+ get => _fadeInAndOut;
+ set => RaiseAndSetIfChanged(ref _fadeInAndOut, value);
+ }
+
public ObservableCollection Modules { get; }
public ProfileModuleViewModel? SelectedModule
@@ -155,6 +163,7 @@ public class ProfileConfigurationEditViewModel : DialogViewModelBase