mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-12 21:38:38 +00:00
Profile editor - Fix race condition causing the editor to fail to activate on suspended profiles
Surface editor - Implemented left-handed preset
This commit is contained in:
parent
108cbaae3d
commit
06c5294e88
@ -157,10 +157,11 @@ internal class DeviceService : IDeviceService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <param name="leftHanded"></param>
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public void AutoArrangeDevices()
|
public void AutoArrangeDevices(bool leftHanded)
|
||||||
{
|
{
|
||||||
SurfaceArrangement surfaceArrangement = SurfaceArrangement.GetDefaultArrangement();
|
SurfaceArrangement surfaceArrangement = SurfaceArrangement.GetDefaultArrangement(leftHanded);
|
||||||
surfaceArrangement.Arrange(_devices);
|
surfaceArrangement.Arrange(_devices);
|
||||||
foreach (ArtemisDevice artemisDevice in _devices)
|
foreach (ArtemisDevice artemisDevice in _devices)
|
||||||
artemisDevice.ApplyDefaultCategories();
|
artemisDevice.ApplyDefaultCategories();
|
||||||
|
|||||||
@ -46,7 +46,8 @@ public interface IDeviceService : IArtemisService
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Applies auto-arranging logic to the surface
|
/// Applies auto-arranging logic to the surface
|
||||||
/// </summary>
|
/// </summary>
|
||||||
void AutoArrangeDevices();
|
/// <param name="leftHanded"></param>
|
||||||
|
void AutoArrangeDevices(bool leftHanded);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Apples the best available to the provided <see cref="ArtemisDevice" />
|
/// Apples the best available to the provided <see cref="ArtemisDevice" />
|
||||||
|
|||||||
@ -48,22 +48,42 @@ internal class SurfaceArrangement
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static SurfaceArrangement GetDefaultArrangement()
|
internal static SurfaceArrangement GetDefaultArrangement(bool leftHanded)
|
||||||
{
|
{
|
||||||
SurfaceArrangement arrangement = new();
|
SurfaceArrangement arrangement = new();
|
||||||
|
|
||||||
SurfaceArrangementType keypad = arrangement.AddType(RGBDeviceType.Keypad, 1);
|
SurfaceArrangementType keyboard, keypad, mousepad, mouse;
|
||||||
|
if (leftHanded)
|
||||||
|
{
|
||||||
|
mousepad = arrangement.AddType(RGBDeviceType.Mousepad, 1);
|
||||||
|
mousepad.AddConfiguration(new SurfaceArrangementConfiguration(null, HorizontalArrangementPosition.Right, VerticalArrangementPosition.Equal, 10));
|
||||||
|
|
||||||
|
mouse = arrangement.AddType(RGBDeviceType.Mouse, 2);
|
||||||
|
mouse.AddConfiguration(new SurfaceArrangementConfiguration(mousepad, HorizontalArrangementPosition.Center, VerticalArrangementPosition.Center, 0));
|
||||||
|
mouse.AddConfiguration(new SurfaceArrangementConfiguration(null, HorizontalArrangementPosition.Right, VerticalArrangementPosition.Center, 10));
|
||||||
|
|
||||||
|
keyboard = arrangement.AddType(RGBDeviceType.Keyboard, 1);
|
||||||
|
keyboard.AddConfiguration(new SurfaceArrangementConfiguration(mousepad, HorizontalArrangementPosition.Right, VerticalArrangementPosition.Equal, 10));
|
||||||
|
keyboard.AddConfiguration(new SurfaceArrangementConfiguration(mouse, HorizontalArrangementPosition.Right, VerticalArrangementPosition.Equal, 100));
|
||||||
|
|
||||||
|
keypad = arrangement.AddType(RGBDeviceType.Keypad, 1);
|
||||||
|
keypad.AddConfiguration(new SurfaceArrangementConfiguration(keyboard, HorizontalArrangementPosition.Equal, VerticalArrangementPosition.Equal, 20));
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
keypad = arrangement.AddType(RGBDeviceType.Keypad, 1);
|
||||||
keypad.AddConfiguration(new SurfaceArrangementConfiguration(null, HorizontalArrangementPosition.Equal, VerticalArrangementPosition.Equal, 20));
|
keypad.AddConfiguration(new SurfaceArrangementConfiguration(null, HorizontalArrangementPosition.Equal, VerticalArrangementPosition.Equal, 20));
|
||||||
|
|
||||||
SurfaceArrangementType keyboard = arrangement.AddType(RGBDeviceType.Keyboard, 1);
|
keyboard = arrangement.AddType(RGBDeviceType.Keyboard, 1);
|
||||||
keyboard.AddConfiguration(new SurfaceArrangementConfiguration(keypad, HorizontalArrangementPosition.Right, VerticalArrangementPosition.Equal, 20));
|
keyboard.AddConfiguration(new SurfaceArrangementConfiguration(keypad, HorizontalArrangementPosition.Right, VerticalArrangementPosition.Equal, 20));
|
||||||
|
|
||||||
SurfaceArrangementType mousepad = arrangement.AddType(RGBDeviceType.Mousepad, 1);
|
mousepad = arrangement.AddType(RGBDeviceType.Mousepad, 1);
|
||||||
mousepad.AddConfiguration(new SurfaceArrangementConfiguration(keyboard, HorizontalArrangementPosition.Right, VerticalArrangementPosition.Equal, 10));
|
mousepad.AddConfiguration(new SurfaceArrangementConfiguration(keyboard, HorizontalArrangementPosition.Right, VerticalArrangementPosition.Equal, 10));
|
||||||
|
|
||||||
SurfaceArrangementType mouse = arrangement.AddType(RGBDeviceType.Mouse, 2);
|
mouse = arrangement.AddType(RGBDeviceType.Mouse, 2);
|
||||||
mouse.AddConfiguration(new SurfaceArrangementConfiguration(mousepad, HorizontalArrangementPosition.Center, VerticalArrangementPosition.Center, 0));
|
mouse.AddConfiguration(new SurfaceArrangementConfiguration(mousepad, HorizontalArrangementPosition.Center, VerticalArrangementPosition.Center, 0));
|
||||||
mouse.AddConfiguration(new SurfaceArrangementConfiguration(keyboard, HorizontalArrangementPosition.Right, VerticalArrangementPosition.Center, 100));
|
mouse.AddConfiguration(new SurfaceArrangementConfiguration(keyboard, HorizontalArrangementPosition.Right, VerticalArrangementPosition.Center, 100));
|
||||||
|
}
|
||||||
|
|
||||||
SurfaceArrangementType headset = arrangement.AddType(RGBDeviceType.Headset, 1);
|
SurfaceArrangementType headset = arrangement.AddType(RGBDeviceType.Headset, 1);
|
||||||
headset.AddConfiguration(new SurfaceArrangementConfiguration(keyboard, HorizontalArrangementPosition.Center, VerticalArrangementPosition.Bottom, 100));
|
headset.AddConfiguration(new SurfaceArrangementConfiguration(keyboard, HorizontalArrangementPosition.Center, VerticalArrangementPosition.Bottom, 100));
|
||||||
|
|||||||
@ -32,7 +32,7 @@ internal class SurfaceArrangementConfiguration
|
|||||||
public int MarginBottom { get; }
|
public int MarginBottom { get; }
|
||||||
public SurfaceArrangement SurfaceArrangement { get; set; }
|
public SurfaceArrangement SurfaceArrangement { get; set; }
|
||||||
|
|
||||||
public bool Apply(List<ArtemisDevice> devices)
|
public bool Apply(List<ArtemisDevice> devicesToArrange, List<ArtemisDevice> devices)
|
||||||
{
|
{
|
||||||
if (Anchor != null && !Anchor.HasDevices(devices))
|
if (Anchor != null && !Anchor.HasDevices(devices))
|
||||||
return false;
|
return false;
|
||||||
@ -42,10 +42,10 @@ internal class SurfaceArrangementConfiguration
|
|||||||
new SurfaceArrangementType(SurfaceArrangement, RGBDeviceType.All, 1).GetEdge(HorizontalPosition, VerticalPosition);
|
new SurfaceArrangementType(SurfaceArrangement, RGBDeviceType.All, 1).GetEdge(HorizontalPosition, VerticalPosition);
|
||||||
|
|
||||||
// Stack multiple devices of the same type vertically if they are wider than they are tall
|
// Stack multiple devices of the same type vertically if they are wider than they are tall
|
||||||
bool stackVertically = devices.Average(d => d.RgbDevice.Size.Width) >= devices.Average(d => d.RgbDevice.Size.Height);
|
bool stackVertically = devicesToArrange.Average(d => d.RgbDevice.Size.Width) >= devicesToArrange.Average(d => d.RgbDevice.Size.Height);
|
||||||
|
|
||||||
ArtemisDevice? previous = null;
|
ArtemisDevice? previous = null;
|
||||||
foreach (ArtemisDevice artemisDevice in devices)
|
foreach (ArtemisDevice artemisDevice in devicesToArrange)
|
||||||
{
|
{
|
||||||
if (previous != null)
|
if (previous != null)
|
||||||
{
|
{
|
||||||
|
|||||||
@ -28,18 +28,18 @@ internal class SurfaceArrangementType
|
|||||||
|
|
||||||
public void Arrange(List<ArtemisDevice> devices)
|
public void Arrange(List<ArtemisDevice> devices)
|
||||||
{
|
{
|
||||||
devices = devices.Where(d => d.DeviceType == DeviceType).ToList();
|
List<ArtemisDevice> devicesToArrange = devices.Where(d => d.DeviceType == DeviceType).ToList();
|
||||||
if (!devices.Any())
|
if (!devicesToArrange.Any())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
AppliedConfiguration = null;
|
AppliedConfiguration = null;
|
||||||
foreach (SurfaceArrangementConfiguration configuration in Configurations)
|
foreach (SurfaceArrangementConfiguration configuration in Configurations)
|
||||||
{
|
{
|
||||||
bool applied = configuration.Apply(devices);
|
bool applied = configuration.Apply(devicesToArrange, devices);
|
||||||
if (applied)
|
if (applied)
|
||||||
{
|
{
|
||||||
AppliedConfiguration = configuration;
|
AppliedConfiguration = configuration;
|
||||||
foreach (ArtemisDevice artemisDevice in devices)
|
foreach (ArtemisDevice artemisDevice in devicesToArrange)
|
||||||
artemisDevice.ZIndex = ZIndex;
|
artemisDevice.ZIndex = ZIndex;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -52,7 +52,7 @@ internal class SurfaceArrangementType
|
|||||||
VerticalArrangementPosition.Equal,
|
VerticalArrangementPosition.Equal,
|
||||||
10
|
10
|
||||||
) {SurfaceArrangement = SurfaceArrangement};
|
) {SurfaceArrangement = SurfaceArrangement};
|
||||||
fallback.Apply(devices);
|
fallback.Apply(devicesToArrange, devices);
|
||||||
AppliedConfiguration = fallback;
|
AppliedConfiguration = fallback;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -185,12 +185,15 @@ internal class ProfileEditorService : IProfileEditorService
|
|||||||
{
|
{
|
||||||
// Activate the profile if one was provided
|
// Activate the profile if one was provided
|
||||||
if (profileConfiguration != null)
|
if (profileConfiguration != null)
|
||||||
|
{
|
||||||
|
_profileService.FocusProfile = profileConfiguration;
|
||||||
_profileService.ActivateProfile(profileConfiguration);
|
_profileService.ActivateProfile(profileConfiguration);
|
||||||
|
}
|
||||||
|
|
||||||
// If there is no profile configuration or module, deliberately set the override to null
|
// If there is no profile configuration or module, deliberately set the override to null
|
||||||
_moduleService.SetActivationOverride(profileConfiguration?.Module);
|
_moduleService.SetActivationOverride(profileConfiguration?.Module);
|
||||||
});
|
});
|
||||||
|
|
||||||
_profileService.FocusProfile = profileConfiguration;
|
|
||||||
_profileConfigurationSubject.OnNext(profileConfiguration);
|
_profileConfigurationSubject.OnNext(profileConfiguration);
|
||||||
|
|
||||||
ChangeTime(TimeSpan.Zero);
|
ChangeTime(TimeSpan.Zero);
|
||||||
|
|||||||
@ -79,11 +79,6 @@ public partial class ProfileTreeViewModel : TreeItemViewModel
|
|||||||
|
|
||||||
public override bool SupportsChildren => true;
|
public override bool SupportsChildren => true;
|
||||||
|
|
||||||
public void UpdateCanPaste()
|
|
||||||
{
|
|
||||||
throw new NotImplementedException();
|
|
||||||
}
|
|
||||||
|
|
||||||
protected override Task ExecuteDuplicate()
|
protected override Task ExecuteDuplicate()
|
||||||
{
|
{
|
||||||
throw new NotSupportedException();
|
throw new NotSupportedException();
|
||||||
|
|||||||
@ -132,6 +132,6 @@ public class SidebarProfileConfigurationViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
public bool Matches(string s)
|
public bool Matches(string s)
|
||||||
{
|
{
|
||||||
return s == $"profile/{ProfileConfiguration.ProfileId}/editor";
|
return s.StartsWith($"profile/{ProfileConfiguration.ProfileId}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -27,6 +27,7 @@ public partial class DefaultEntryItemViewModel : ActivatableViewModelBase
|
|||||||
private readonly IWorkshopService _workshopService;
|
private readonly IWorkshopService _workshopService;
|
||||||
private readonly IWindowService _windowService;
|
private readonly IWindowService _windowService;
|
||||||
private readonly IPluginManagementService _pluginManagementService;
|
private readonly IPluginManagementService _pluginManagementService;
|
||||||
|
private readonly IProfileService _profileService;
|
||||||
private readonly ISettingsVmFactory _settingsVmFactory;
|
private readonly ISettingsVmFactory _settingsVmFactory;
|
||||||
private readonly Progress<StreamProgress> _progress = new();
|
private readonly Progress<StreamProgress> _progress = new();
|
||||||
|
|
||||||
@ -34,13 +35,19 @@ public partial class DefaultEntryItemViewModel : ActivatableViewModelBase
|
|||||||
[Notify] private bool _shouldInstall;
|
[Notify] private bool _shouldInstall;
|
||||||
[Notify] private float _installProgress;
|
[Notify] private float _installProgress;
|
||||||
|
|
||||||
public DefaultEntryItemViewModel(ILogger logger, IEntrySummary entry, IWorkshopService workshopService, IWindowService windowService, IPluginManagementService pluginManagementService,
|
public DefaultEntryItemViewModel(ILogger logger,
|
||||||
|
IEntrySummary entry,
|
||||||
|
IWorkshopService workshopService,
|
||||||
|
IWindowService windowService,
|
||||||
|
IPluginManagementService pluginManagementService,
|
||||||
|
IProfileService profileService,
|
||||||
ISettingsVmFactory settingsVmFactory)
|
ISettingsVmFactory settingsVmFactory)
|
||||||
{
|
{
|
||||||
_logger = logger;
|
_logger = logger;
|
||||||
_workshopService = workshopService;
|
_workshopService = workshopService;
|
||||||
_windowService = windowService;
|
_windowService = windowService;
|
||||||
_pluginManagementService = pluginManagementService;
|
_pluginManagementService = pluginManagementService;
|
||||||
|
_profileService = profileService;
|
||||||
_settingsVmFactory = settingsVmFactory;
|
_settingsVmFactory = settingsVmFactory;
|
||||||
Entry = entry;
|
Entry = entry;
|
||||||
|
|
||||||
@ -62,19 +69,18 @@ public partial class DefaultEntryItemViewModel : ActivatableViewModelBase
|
|||||||
|
|
||||||
if (!result.IsSuccess)
|
if (!result.IsSuccess)
|
||||||
{
|
{
|
||||||
await _windowService.CreateContentDialog().WithTitle("Failed to install entry")
|
await _windowService.CreateContentDialog()
|
||||||
|
.WithTitle("Failed to install entry")
|
||||||
.WithContent($"Failed to install entry '{Entry.Name}' ({Entry.Id}): {result.Message}")
|
.WithContent($"Failed to install entry '{Entry.Name}' ({Entry.Id}): {result.Message}")
|
||||||
.WithCloseButtonText("Skip and continue")
|
.WithCloseButtonText("Skip and continue")
|
||||||
.ShowAsync();
|
.ShowAsync();
|
||||||
}
|
}
|
||||||
// If the entry is a plugin, enable the plugin and all features
|
// If the entry is a plugin, enable the plugin and all features
|
||||||
else if (result.Entry?.EntryType == EntryType.Plugin)
|
else if (result.Entry?.EntryType == EntryType.Plugin)
|
||||||
{
|
|
||||||
await EnablePluginAndFeatures(result.Entry);
|
await EnablePluginAndFeatures(result.Entry);
|
||||||
} else if (result.Entry?.EntryType == EntryType.Profile)
|
// If the entry is a profile, move it to the General profile category
|
||||||
{
|
else if (result.Entry?.EntryType == EntryType.Profile)
|
||||||
|
MoveProfileToGeneral(result.Entry);
|
||||||
}
|
|
||||||
|
|
||||||
return result.IsSuccess;
|
return result.IsSuccess;
|
||||||
}
|
}
|
||||||
@ -117,4 +123,21 @@ public partial class DefaultEntryItemViewModel : ActivatableViewModelBase
|
|||||||
await _windowService.ShowDialogAsync(new PluginSettingsWindowViewModel(viewModel));
|
await _windowService.ShowDialogAsync(new PluginSettingsWindowViewModel(viewModel));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void MoveProfileToGeneral(InstalledEntry entry)
|
||||||
|
{
|
||||||
|
if (!entry.TryGetMetadata("ProfileId", out Guid profileId))
|
||||||
|
return;
|
||||||
|
|
||||||
|
ProfileConfiguration? profile = _profileService.ProfileCategories.SelectMany(c => c.ProfileConfigurations).FirstOrDefault(c => c.ProfileId == profileId);
|
||||||
|
if (profile == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ProfileCategory category = _profileService.ProfileCategories.FirstOrDefault(c => c.Name == "General") ?? _profileService.CreateProfileCategory("General", true);
|
||||||
|
if (category.ProfileConfigurations.Contains(profile))
|
||||||
|
return;
|
||||||
|
|
||||||
|
category.AddProfileConfiguration(profile, null);
|
||||||
|
_profileService.SaveProfileCategory(category);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@ -24,15 +24,14 @@
|
|||||||
HorizontalAlignment="Right"
|
HorizontalAlignment="Right"
|
||||||
Margin="0 0 10 0"
|
Margin="0 0 10 0"
|
||||||
Width="280"
|
Width="280"
|
||||||
Height="280"
|
Height="280">
|
||||||
IsEnabled="False">
|
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<avalonia:MaterialIcon Kind="HandBackLeft" Width="150" Height="150" HorizontalAlignment="Center" />
|
<avalonia:MaterialIcon Kind="HandBackLeft" Width="150" Height="150" HorizontalAlignment="Center" />
|
||||||
<TextBlock TextAlignment="Center" Classes="h4" Margin="0 10 0 0">
|
<TextBlock TextAlignment="Center" Classes="h4" Margin="0 10 0 0">
|
||||||
Left-handed preset (NYI)
|
Left-handed preset
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
<TextBlock TextAlignment="Center" Classes="subtitle" TextWrapping="Wrap">
|
<TextBlock TextAlignment="Center" Classes="subtitle" TextWrapping="Wrap">
|
||||||
A preset with the mouse on the left side of the keyboard
|
A preset with the mouse on the left side of the keyboard (are you the 10%?)
|
||||||
</TextBlock>
|
</TextBlock>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Button>
|
</Button>
|
||||||
|
|||||||
@ -27,9 +27,7 @@ public class SurfaceStepViewModel : WizardStepViewModel
|
|||||||
|
|
||||||
private void ExecuteSelectLayout(string layout)
|
private void ExecuteSelectLayout(string layout)
|
||||||
{
|
{
|
||||||
// TODO: Implement the layout
|
_deviceService.AutoArrangeDevices(layout == "left");
|
||||||
_deviceService.AutoArrangeDevices();
|
|
||||||
|
|
||||||
Wizard.ChangeScreen<SettingsStepViewModel>();
|
Wizard.ChangeScreen<SettingsStepViewModel>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -13,6 +13,7 @@ using Artemis.UI.Shared;
|
|||||||
using Artemis.UI.Shared.Routing;
|
using Artemis.UI.Shared.Routing;
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using Avalonia;
|
using Avalonia;
|
||||||
|
using FluentAvalonia.UI.Controls;
|
||||||
using PropertyChanged.SourceGenerator;
|
using PropertyChanged.SourceGenerator;
|
||||||
using ReactiveUI;
|
using ReactiveUI;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
@ -180,11 +181,18 @@ public partial class SurfaceEditorViewModel : RoutableScreen, IMainScreenViewMod
|
|||||||
|
|
||||||
private async Task ExecuteAutoArrange()
|
private async Task ExecuteAutoArrange()
|
||||||
{
|
{
|
||||||
bool confirmed = await _windowService.ShowConfirmContentDialog("Auto-arrange layout", "Are you sure you want to auto-arrange your layout? Your current settings will be overwritten.");
|
ContentDialogResult contentDialogResult = await _windowService.CreateContentDialog()
|
||||||
if (!confirmed)
|
.WithTitle("Auto-arrange layout")
|
||||||
return;
|
.WithContent("Which preset would you like to apply? Your current settings will be overwritten.")
|
||||||
|
.HavingPrimaryButton(b => b.WithText("Left-handed preset"))
|
||||||
|
.HavingSecondaryButton(b => b.WithText("Right-handed preset"))
|
||||||
|
.WithCloseButtonText("Cancel")
|
||||||
|
.ShowAsync();
|
||||||
|
|
||||||
_deviceService.AutoArrangeDevices();
|
if (contentDialogResult == ContentDialogResult.Primary)
|
||||||
|
_deviceService.AutoArrangeDevices(true);
|
||||||
|
else if (contentDialogResult == ContentDialogResult.Secondary)
|
||||||
|
_deviceService.AutoArrangeDevices(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RenderServiceOnFrameRendering(object? sender, FrameRenderingEventArgs e)
|
private void RenderServiceOnFrameRendering(object? sender, FrameRenderingEventArgs e)
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user