diff --git a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionEvent.cs b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionEvent.cs
index 8ae6d5411..64529c531 100644
--- a/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionEvent.cs
+++ b/src/Artemis.Core/Models/Profile/Conditions/DataModelConditionEvent.cs
@@ -12,7 +12,6 @@ namespace Artemis.Core
{
private bool _disposed;
private bool _reinitializing;
- private DateTime _lastTrigger;
///
/// Creates a new instance of the class
@@ -39,6 +38,8 @@ namespace Artemis.Core
///
public DataModelPath? EventPath { get; private set; }
+ public DateTime LastTrigger { get; private set; }
+
///
/// Gets or sets the type of argument the event provides
///
@@ -55,10 +56,10 @@ namespace Artemis.Core
if (EventPath?.GetValue() is not IDataModelEvent dataModelEvent)
return false;
// Only evaluate to true once every time the event has been triggered since the last evaluation
- if (dataModelEvent.LastTrigger <= _lastTrigger)
+ if (dataModelEvent.LastTrigger <= LastTrigger)
return false;
- _lastTrigger = DateTime.Now;
+ LastTrigger = DateTime.Now;
// If there is a child (root group), it must evaluate to true whenever the event triggered
if (Children.Any())
@@ -171,8 +172,8 @@ namespace Artemis.Core
AddChild(new DataModelConditionGroup(this));
}
- if (EventPath?.GetValue() is IDataModelEvent dataModelEvent)
- _lastTrigger = dataModelEvent.LastTrigger;
+ if (EventPath?.GetValue() is IDataModelEvent dataModelEvent)
+ LastTrigger = dataModelEvent.LastTrigger;
}
private Type? GetEventArgumentType()
diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs
index ace2734a9..9a98dfcc2 100644
--- a/src/Artemis.Core/Models/Profile/Layer.cs
+++ b/src/Artemis.Core/Models/Profile/Layer.cs
@@ -287,7 +287,7 @@ namespace Artemis.Core
if (!Enabled || Path == null || LayerShape?.Path == null || !General.PropertiesInitialized || !Transform.PropertiesInitialized)
return;
// Ensure the brush is ready
- if (LayerBrush?.BaseProperties?.PropertiesInitialized == false)
+ if (LayerBrush == null || LayerBrush?.BaseProperties?.PropertiesInitialized == false)
return;
RenderTimeline(Timeline, canvas);
diff --git a/src/Artemis.Core/Models/Surface/ArtemisDevice.cs b/src/Artemis.Core/Models/Surface/ArtemisDevice.cs
index 661130160..9146097e2 100644
--- a/src/Artemis.Core/Models/Surface/ArtemisDevice.cs
+++ b/src/Artemis.Core/Models/Surface/ArtemisDevice.cs
@@ -306,7 +306,7 @@ namespace Artemis.Core
{
// Take out invalid file name chars, may not be perfect but neither are you
string fileName = System.IO.Path.GetInvalidFileNameChars().Aggregate(RgbDevice.DeviceInfo.Model, (current, c) => current.Replace(c, '-'));
- if (RgbDevice is IKeyboard)
+ if (RgbDevice.DeviceInfo.DeviceType == RGBDeviceType.Keyboard)
fileName = $"{fileName}-{PhysicalLayout.ToString().ToUpper()}";
if (includeExtension)
fileName = $"{fileName}.xml";
@@ -353,7 +353,7 @@ namespace Artemis.Core
{
RgbDevice.Rotation = DeviceEntity.Rotation;
RgbDevice.Scale = DeviceEntity.Scale;
-
+
// Workaround for device rotation not applying
if (DeviceEntity.X == 0 && DeviceEntity.Y == 0)
RgbDevice.Location = new Point(1, 1);
@@ -388,14 +388,19 @@ namespace Artemis.Core
private void ApplyKeyboardLayout()
{
- if (!(RgbDevice is IKeyboard keyboard))
+ if (RgbDevice.DeviceInfo.DeviceType != RGBDeviceType.Keyboard)
return;
+ IKeyboard? keyboard = RgbDevice as IKeyboard;
// If supported, detect the device layout so that we can load the correct one
- if (DeviceProvider.CanDetectLogicalLayout)
- LogicalLayout = DeviceProvider.GetLogicalLayout(keyboard);
- if (DeviceProvider.CanDetectPhysicalLayout)
+ if (DeviceProvider.CanDetectPhysicalLayout && keyboard != null)
PhysicalLayout = (KeyboardLayoutType) keyboard.DeviceInfo.Layout;
+ else
+ PhysicalLayout = (KeyboardLayoutType) DeviceEntity.PhysicalLayout;
+ if (DeviceProvider.CanDetectLogicalLayout && keyboard != null)
+ LogicalLayout = DeviceProvider.GetLogicalLayout(keyboard);
+ else
+ LogicalLayout = DeviceEntity.LogicalLayout;
}
#region Events
diff --git a/src/Artemis.Core/Models/Surface/Layout/ArtemisLayout.cs b/src/Artemis.Core/Models/Surface/Layout/ArtemisLayout.cs
index cc837ca3b..7ff43d6ef 100644
--- a/src/Artemis.Core/Models/Surface/Layout/ArtemisLayout.cs
+++ b/src/Artemis.Core/Models/Surface/Layout/ArtemisLayout.cs
@@ -65,12 +65,6 @@ namespace Artemis.Core
///
public LayoutCustomDeviceData LayoutCustomDeviceData { get; private set; } = null!;
- public void ReloadFromDisk()
- {
- Leds.Clear();
- LoadLayout();
- }
-
internal void ApplyDevice(ArtemisDevice artemisDevice)
{
Device = artemisDevice;
diff --git a/src/Artemis.Core/Services/DeviceService.cs b/src/Artemis.Core/Services/DeviceService.cs
index 68329ac77..e39616844 100644
--- a/src/Artemis.Core/Services/DeviceService.cs
+++ b/src/Artemis.Core/Services/DeviceService.cs
@@ -1,4 +1,5 @@
-using System.Linq;
+using System.Collections.Generic;
+using System.Linq;
using System.Threading.Tasks;
using RGB.NET.Core;
diff --git a/src/Artemis.Core/Services/WebServer/EndPoints/DataModelJsonPluginEndPoint.cs b/src/Artemis.Core/Services/WebServer/EndPoints/DataModelJsonPluginEndPoint.cs
index 30532aa2b..052c9c5a3 100644
--- a/src/Artemis.Core/Services/WebServer/EndPoints/DataModelJsonPluginEndPoint.cs
+++ b/src/Artemis.Core/Services/WebServer/EndPoints/DataModelJsonPluginEndPoint.cs
@@ -15,9 +15,18 @@ namespace Artemis.Core.Services
///
public class DataModelJsonPluginEndPoint : PluginEndPoint where T : DataModel
{
+ private readonly ProfileModule? _profileModule;
private readonly Module? _module;
private readonly DataModelExpansion? _dataModelExpansion;
+ internal DataModelJsonPluginEndPoint(ProfileModule profileModule, string name, PluginsModule pluginsModule) : base(profileModule, name, pluginsModule)
+ {
+ _profileModule = profileModule ?? throw new ArgumentNullException(nameof(profileModule));
+
+ ThrowOnFail = true;
+ Accepts = MimeType.Json;
+ }
+
internal DataModelJsonPluginEndPoint(Module module, string name, PluginsModule pluginsModule) : base(module, name, pluginsModule)
{
_module = module ?? throw new ArgumentNullException(nameof(module));
@@ -54,7 +63,9 @@ namespace Artemis.Core.Services
using TextReader reader = context.OpenRequestText();
try
{
- if (_module != null)
+ if (_profileModule != null)
+ JsonConvert.PopulateObject(await reader.ReadToEndAsync(), _profileModule.DataModel);
+ else if (_module != null)
JsonConvert.PopulateObject(await reader.ReadToEndAsync(), _module.DataModel);
else
JsonConvert.PopulateObject(await reader.ReadToEndAsync(), _dataModelExpansion!.DataModel);
diff --git a/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs b/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs
index ef98d3fa0..d88e3da3b 100644
--- a/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs
+++ b/src/Artemis.Core/Services/WebServer/Interfaces/IWebServerService.cs
@@ -54,6 +54,15 @@ namespace Artemis.Core.Services
/// The resulting end point
DataModelJsonPluginEndPoint AddDataModelJsonEndPoint(Module module, string endPointName) where T : DataModel;
+ ///
+ /// Adds a new endpoint that directly maps received JSON to the data model of the provided .
+ ///
+ /// The data model type of the module
+ /// The module whose datamodel to apply the received JSON to
+ /// The name of the end point, must be unique
+ /// The resulting end point
+ DataModelJsonPluginEndPoint AddDataModelJsonEndPoint(ProfileModule profileModule, string endPointName) where T : DataModel;
+
///
/// Adds a new endpoint that directly maps received JSON to the data model of the provided .
///
diff --git a/src/Artemis.Core/Services/WebServer/WebServerService.cs b/src/Artemis.Core/Services/WebServer/WebServerService.cs
index 8de5ce9e4..d74035da2 100644
--- a/src/Artemis.Core/Services/WebServer/WebServerService.cs
+++ b/src/Artemis.Core/Services/WebServer/WebServerService.cs
@@ -136,6 +136,15 @@ namespace Artemis.Core.Services
return endPoint;
}
+ public DataModelJsonPluginEndPoint AddDataModelJsonEndPoint(ProfileModule profileModule, string endPointName) where T : DataModel
+ {
+ if (profileModule == null) throw new ArgumentNullException(nameof(profileModule));
+ if (endPointName == null) throw new ArgumentNullException(nameof(endPointName));
+ DataModelJsonPluginEndPoint endPoint = new(profileModule, endPointName, PluginsModule);
+ PluginsModule.AddPluginEndPoint(endPoint);
+ return endPoint;
+ }
+
public DataModelJsonPluginEndPoint AddDataModelJsonEndPoint(DataModelExpansion dataModelExpansion, string endPointName) where T : DataModel
{
if (dataModelExpansion == null) throw new ArgumentNullException(nameof(dataModelExpansion));
diff --git a/src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs b/src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs
index 397dd2dae..21e82e6b1 100644
--- a/src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs
+++ b/src/Artemis.UI.Shared/Controls/DeviceVisualizer.cs
@@ -288,12 +288,12 @@ namespace Artemis.UI.Shared
private void DeviceUpdated(object? sender, EventArgs e)
{
- SetupForDevice();
+ Execute.PostToUIThread(SetupForDevice);
}
private void DevicePropertyChanged(object? sender, PropertyChangedEventArgs e)
{
- SetupForDevice();
+ Execute.PostToUIThread(SetupForDevice);
}
private void Render()
diff --git a/src/Artemis.UI.Shared/Controls/DeviceVisualizerLed.cs b/src/Artemis.UI.Shared/Controls/DeviceVisualizerLed.cs
index 1e96549a9..35adaf092 100644
--- a/src/Artemis.UI.Shared/Controls/DeviceVisualizerLed.cs
+++ b/src/Artemis.UI.Shared/Controls/DeviceVisualizerLed.cs
@@ -12,9 +12,12 @@ namespace Artemis.UI.Shared
{
internal class DeviceVisualizerLed
{
+ private const byte Dimmed = 100;
+ private const byte NonDimmed = 255;
+
private SolidColorBrush? _renderColorBrush;
private Color _renderColor;
-
+
public DeviceVisualizerLed(ArtemisLed led)
{
Led = led;
@@ -48,7 +51,8 @@ namespace Artemis.UI.Shared
byte g = Led.RgbLed.Color.GetG();
byte b = Led.RgbLed.Color.GetB();
- _renderColor.A = isDimmed ? 100 : 255;
+ _renderColor.A = (byte)(isDimmed ? 100 : 255);
+ _renderColor.A = isDimmed ? Dimmed : NonDimmed;
_renderColor.R = r;
_renderColor.G = g;
_renderColor.B = b;
diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj
index 362b05fa9..451ff0b03 100644
--- a/src/Artemis.UI/Artemis.UI.csproj
+++ b/src/Artemis.UI/Artemis.UI.csproj
@@ -126,6 +126,11 @@
+
+
+
+
+
@@ -306,6 +311,11 @@
+
+
+
+
+
diff --git a/src/Artemis.UI/Behaviors/HighlightTermBehavior.cs b/src/Artemis.UI/Behaviors/HighlightTermBehavior.cs
new file mode 100644
index 000000000..2d30ae887
--- /dev/null
+++ b/src/Artemis.UI/Behaviors/HighlightTermBehavior.cs
@@ -0,0 +1,169 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text.RegularExpressions;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Documents;
+using System.Windows.Media;
+
+namespace Artemis.UI.Behaviors
+{
+ // Source: https://stackoverflow.com/a/60474831/5015269
+ // Made some changes to add a foreground and background property
+ public static class HighlightTermBehavior
+ {
+ public static readonly DependencyProperty TextProperty = DependencyProperty.RegisterAttached(
+ "Text",
+ typeof(string),
+ typeof(HighlightTermBehavior),
+ new FrameworkPropertyMetadata("", OnTextChanged));
+
+ public static readonly DependencyProperty TermToBeHighlightedProperty = DependencyProperty.RegisterAttached(
+ "TermToBeHighlighted",
+ typeof(string),
+ typeof(HighlightTermBehavior),
+ new FrameworkPropertyMetadata("", OnTextChanged));
+
+ public static readonly DependencyProperty HighlightForegroundProperty = DependencyProperty.RegisterAttached(
+ "HighlightForeground",
+ typeof(Color?),
+ typeof(HighlightTermBehavior),
+ new FrameworkPropertyMetadata(null, OnTextChanged));
+
+ public static readonly DependencyProperty HighlightBackgroundProperty = DependencyProperty.RegisterAttached(
+ "HighlightBackground",
+ typeof(Color?),
+ typeof(HighlightTermBehavior),
+ new FrameworkPropertyMetadata(null, OnTextChanged));
+
+ public static string GetText(FrameworkElement frameworkElement)
+ {
+ return (string) frameworkElement.GetValue(TextProperty);
+ }
+
+ public static void SetText(FrameworkElement frameworkElement, string value)
+ {
+ frameworkElement.SetValue(TextProperty, value);
+ }
+
+ public static string GetTermToBeHighlighted(FrameworkElement frameworkElement)
+ {
+ return (string) frameworkElement.GetValue(TermToBeHighlightedProperty);
+ }
+
+ public static void SetTermToBeHighlighted(FrameworkElement frameworkElement, string value)
+ {
+ frameworkElement.SetValue(TermToBeHighlightedProperty, value);
+ }
+
+ public static void SetHighlightForeground(FrameworkElement frameworkElement, Color? value)
+ {
+ frameworkElement.SetValue(HighlightForegroundProperty, value);
+ }
+
+ public static Color? GetHighlightForeground(FrameworkElement frameworkElement)
+ {
+ return (Color?) frameworkElement.GetValue(HighlightForegroundProperty);
+ }
+
+ public static void SetHighlightBackground(FrameworkElement frameworkElement, Color? value)
+ {
+ frameworkElement.SetValue(HighlightBackgroundProperty, value);
+ }
+
+ public static Color? GetHighlightBackground(FrameworkElement frameworkElement)
+ {
+ return (Color?) frameworkElement.GetValue(HighlightBackgroundProperty);
+ }
+
+ public static List SplitTextIntoTermAndNotTermParts(string text, string term)
+ {
+ if (string.IsNullOrEmpty(text))
+ return new List {string.Empty};
+
+ return Regex.Split(text, $@"({Regex.Escape(term)})", RegexOptions.IgnoreCase)
+ .Where(p => p != string.Empty)
+ .ToList();
+ }
+
+
+ private static void OnTextChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+ {
+ if (d is TextBlock textBlock)
+ SetTextBlockTextAndHighlightTerm(textBlock, GetText(textBlock), GetTermToBeHighlighted(textBlock));
+ }
+
+ private static void SetTextBlockTextAndHighlightTerm(TextBlock textBlock, string text, string termToBeHighlighted)
+ {
+ textBlock.Text = string.Empty;
+
+ if (TextIsEmpty(text))
+ return;
+
+ if (TextIsNotContainingTermToBeHighlighted(text, termToBeHighlighted))
+ {
+ AddPartToTextBlock(textBlock, text);
+ return;
+ }
+
+ List textParts = SplitTextIntoTermAndNotTermParts(text, termToBeHighlighted);
+
+ foreach (string textPart in textParts)
+ AddPartToTextBlockAndHighlightIfNecessary(textBlock, termToBeHighlighted, textPart);
+ }
+
+ private static bool TextIsEmpty(string text)
+ {
+ return text.Length == 0;
+ }
+
+ private static bool TextIsNotContainingTermToBeHighlighted(string text, string termToBeHighlighted)
+ {
+ if (text == null || termToBeHighlighted == null)
+ return true;
+ return text.Contains(termToBeHighlighted, StringComparison.OrdinalIgnoreCase) == false;
+ }
+
+ private static void AddPartToTextBlockAndHighlightIfNecessary(TextBlock textBlock, string termToBeHighlighted, string textPart)
+ {
+ if (textPart.Equals(termToBeHighlighted, StringComparison.OrdinalIgnoreCase))
+ AddHighlightedPartToTextBlock(textBlock, textPart);
+ else
+ AddPartToTextBlock(textBlock, textPart);
+ }
+
+ private static void AddPartToTextBlock(TextBlock textBlock, string part)
+ {
+ textBlock.Inlines.Add(new Run {Text = part});
+ }
+
+ private static void AddHighlightedPartToTextBlock(TextBlock textBlock, string part)
+ {
+ Color? foreground = GetHighlightForeground(textBlock);
+ Color? background = GetHighlightBackground(textBlock);
+
+ if (background == null)
+ {
+ Run run = new() {Text = part, FontWeight = FontWeights.ExtraBold};
+ if (foreground != null)
+ run.Foreground = new SolidColorBrush(foreground.Value);
+ textBlock.Inlines.Add(run);
+ return;
+ }
+
+ Border border = new()
+ {
+ Background = new SolidColorBrush(background.Value),
+ BorderThickness = new Thickness(0),
+ CornerRadius = new CornerRadius(2),
+ Child = new TextBlock {Text = part, FontWeight = FontWeights.Bold},
+ Padding = new Thickness(1),
+ Margin = new Thickness(-1, -5, -1, -5)
+ };
+ if (foreground != null)
+ ((TextBlock) border.Child).Foreground = new SolidColorBrush(foreground.Value);
+ textBlock.Inlines.Add(border);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Bootstrapper.cs b/src/Artemis.UI/Bootstrapper.cs
index 5544c2307..585b1b1a4 100644
--- a/src/Artemis.UI/Bootstrapper.cs
+++ b/src/Artemis.UI/Bootstrapper.cs
@@ -90,6 +90,9 @@ namespace Artemis.UI
IRegistrationService registrationService = Kernel.Get();
registrationService.RegisterInputProvider();
registrationService.RegisterControllers();
+
+ // Initialize background services
+ Kernel.Get();
}
protected override void ConfigureIoC(IKernel kernel)
diff --git a/src/Artemis.UI/Resources/Images/PhysicalLayouts/abnt.png b/src/Artemis.UI/Resources/Images/PhysicalLayouts/abnt.png
new file mode 100644
index 000000000..dc7593429
Binary files /dev/null and b/src/Artemis.UI/Resources/Images/PhysicalLayouts/abnt.png differ
diff --git a/src/Artemis.UI/Resources/Images/PhysicalLayouts/ansi.png b/src/Artemis.UI/Resources/Images/PhysicalLayouts/ansi.png
new file mode 100644
index 000000000..940a8f233
Binary files /dev/null and b/src/Artemis.UI/Resources/Images/PhysicalLayouts/ansi.png differ
diff --git a/src/Artemis.UI/Resources/Images/PhysicalLayouts/iso.png b/src/Artemis.UI/Resources/Images/PhysicalLayouts/iso.png
new file mode 100644
index 000000000..ee4272e81
Binary files /dev/null and b/src/Artemis.UI/Resources/Images/PhysicalLayouts/iso.png differ
diff --git a/src/Artemis.UI/Resources/Images/PhysicalLayouts/jis.png b/src/Artemis.UI/Resources/Images/PhysicalLayouts/jis.png
new file mode 100644
index 000000000..d872ddab3
Binary files /dev/null and b/src/Artemis.UI/Resources/Images/PhysicalLayouts/jis.png differ
diff --git a/src/Artemis.UI/Resources/Images/PhysicalLayouts/ks.png b/src/Artemis.UI/Resources/Images/PhysicalLayouts/ks.png
new file mode 100644
index 000000000..898f8a85e
Binary files /dev/null and b/src/Artemis.UI/Resources/Images/PhysicalLayouts/ks.png differ
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/Abstract/DataModelConditionPredicateViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/Abstract/DataModelConditionPredicateViewModel.cs
index f0a4a4ba5..6efb8a33a 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/Abstract/DataModelConditionPredicateViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/Abstract/DataModelConditionPredicateViewModel.cs
@@ -67,6 +67,11 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions.Abstract
protected SolidColorBrush LeftSideColor { get; set; }
+ public override void Evaluate()
+ {
+ IsConditionMet = DataModelConditionPredicate.Evaluate();
+ }
+
public override void Delete()
{
base.Delete();
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/Abstract/DataModelConditionViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/Abstract/DataModelConditionViewModel.cs
index 0cae105e4..b2f94a711 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/Abstract/DataModelConditionViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/Abstract/DataModelConditionViewModel.cs
@@ -8,6 +8,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions.Abstract
public abstract class DataModelConditionViewModel : Conductor.Collection.AllActive
{
private DataModelDynamicViewModel _leftSideSelectionViewModel;
+ private bool _isConditionMet;
protected DataModelConditionViewModel(DataModelConditionPart model)
{
@@ -22,8 +23,17 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions.Abstract
set => SetAndNotify(ref _leftSideSelectionViewModel, value);
}
+ public bool IsConditionMet
+ {
+ get => _isConditionMet;
+ set => SetAndNotify(ref _isConditionMet, value);
+ }
+
+
public abstract void Update();
+ public abstract void Evaluate();
+
public virtual void Delete()
{
Model.Parent.RemoveChild(Model);
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionEventView.xaml b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionEventView.xaml
index f71fb5e79..8b9a2b81b 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionEventView.xaml
+++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionEventView.xaml
@@ -13,7 +13,14 @@
+
+
+
+
+
+
+
@@ -21,6 +28,7 @@
+
@@ -52,7 +60,37 @@
triggered
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionEventViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionEventViewModel.cs
index b22a5fe17..e864ce342 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionEventViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionEventViewModel.cs
@@ -15,6 +15,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
private readonly IDataModelConditionsVmFactory _dataModelConditionsVmFactory;
private readonly IDataModelUIService _dataModelUIService;
private readonly IProfileEditorService _profileEditorService;
+ private DateTime _lastTrigger;
public DataModelConditionEventViewModel(DataModelConditionEvent dataModelConditionEvent,
IProfileEditorService profileEditorService,
@@ -24,10 +25,18 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
_profileEditorService = profileEditorService;
_dataModelUIService = dataModelUIService;
_dataModelConditionsVmFactory = dataModelConditionsVmFactory;
+
+ _lastTrigger = DataModelConditionEvent.LastTrigger;
}
public DataModelConditionEvent DataModelConditionEvent => (DataModelConditionEvent) Model;
+ public DateTime LastTrigger
+ {
+ get => _lastTrigger;
+ set => SetAndNotify(ref _lastTrigger, value);
+ }
+
public void Initialize()
{
LeftSideSelectionViewModel = _dataModelUIService.GetDynamicSelectionViewModel(_profileEditorService.GetCurrentModule());
@@ -36,7 +45,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
IReadOnlyCollection editors = _dataModelUIService.RegisteredDataModelEditors;
List supportedInputTypes = new() {typeof(DataModelEvent), typeof(DataModelEvent<>)};
-
+
LeftSideSelectionViewModel.FilterTypes = supportedInputTypes.ToArray();
LeftSideSelectionViewModel.ButtonBrush = new SolidColorBrush(Color.FromRgb(185, 164, 10));
LeftSideSelectionViewModel.Placeholder = "Select an event";
@@ -74,6 +83,12 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
childViewModel.Update();
}
+ public override void Evaluate()
+ {
+ LastTrigger = DataModelConditionEvent.LastTrigger;
+ IsConditionMet = DataModelConditionEvent.Evaluate();
+ }
+
public void ApplyEvent()
{
DataModelConditionEvent.UpdateEvent(LeftSideSelectionViewModel.DataModelPath);
@@ -104,7 +119,7 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
LeftSideSelectionViewModel.Dispose();
LeftSideSelectionViewModel.PropertySelected -= LeftSideSelectionViewModelOnPropertySelected;
}
-
+
#endregion
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionGroupView.xaml b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionGroupView.xaml
index 0e4f1b687..421cf840d 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionGroupView.xaml
+++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/DataModelConditionGroupView.xaml
@@ -28,6 +28,7 @@
+
@@ -115,9 +116,9 @@
-
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionGeneralPredicateViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionGeneralPredicateViewModel.cs
index 0ea8d96ee..96c2382b0 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionGeneralPredicateViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionGeneralPredicateViewModel.cs
@@ -42,5 +42,10 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
{
return LeftSideSelectionViewModel.DataModelPath?.GetPropertyType();
}
+
+ public override void Evaluate()
+ {
+ IsConditionMet = DataModelConditionPredicate.Evaluate();
+ }
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionListPredicateViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionListPredicateViewModel.cs
index fbc4730b1..2ca951ee8 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionListPredicateViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/Conditions/Predicate/DataModelConditionListPredicateViewModel.cs
@@ -81,5 +81,10 @@ namespace Artemis.UI.Screens.ProfileEditor.Conditions
return wrapper.CreateViewModel(_dataModelUIService, new DataModelUpdateConfiguration(true));
}
+
+ public override void Evaluate()
+ {
+ throw new NotImplementedException();
+ }
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml
index 05c33df00..eed55746a 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml
+++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsView.xaml
@@ -24,9 +24,19 @@
-
- Display conditions
-
+
+
+ Display conditions
+
+
+ Not applied during editing
+
+
+
diff --git a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs
index 3f79b19e3..b6bbf11aa 100644
--- a/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs
+++ b/src/Artemis.UI/Screens/ProfileEditor/DisplayConditions/DisplayConditionsViewModel.cs
@@ -1,6 +1,7 @@
using System;
using System.Linq;
using Artemis.Core;
+using Artemis.Core.Services;
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Screens.ProfileEditor.Conditions;
using Artemis.UI.Shared;
@@ -12,15 +13,17 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
public class DisplayConditionsViewModel : Conductor, IProfileEditorPanelViewModel
{
private readonly IDataModelConditionsVmFactory _dataModelConditionsVmFactory;
+ private readonly ICoreService _coreService;
private readonly IProfileEditorService _profileEditorService;
private RenderProfileElement _renderProfileElement;
private bool _displayStartHint;
private bool _isEventCondition;
- public DisplayConditionsViewModel(IProfileEditorService profileEditorService, IDataModelConditionsVmFactory dataModelConditionsVmFactory)
+ public DisplayConditionsViewModel(IProfileEditorService profileEditorService, IDataModelConditionsVmFactory dataModelConditionsVmFactory, ICoreService coreService)
{
_profileEditorService = profileEditorService;
_dataModelConditionsVmFactory = dataModelConditionsVmFactory;
+ _coreService = coreService;
}
public bool DisplayStartHint
@@ -87,12 +90,14 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
protected override void OnInitialActivate()
{
_profileEditorService.ProfileElementSelected += ProfileEditorServiceOnProfileElementSelected;
+ _coreService.FrameRendered += CoreServiceOnFrameRendered;
base.OnInitialActivate();
}
protected override void OnClose()
{
_profileEditorService.ProfileElementSelected -= ProfileEditorServiceOnProfileElementSelected;
+ _coreService.FrameRendered -= CoreServiceOnFrameRendered;
base.OnClose();
}
@@ -131,6 +136,11 @@ namespace Artemis.UI.Screens.ProfileEditor.DisplayConditions
RenderProfileElement.DisplayCondition.ChildRemoved += DisplayConditionOnChildrenModified;
}
+ private void CoreServiceOnFrameRendered(object? sender, FrameRenderedEventArgs e)
+ {
+ ActiveItem?.Evaluate();
+ }
+
private void DisplayConditionOnChildrenModified(object sender, EventArgs e)
{
DisplayStartHint = !RenderProfileElement.DisplayCondition.Children.Any();
diff --git a/src/Artemis.UI/Screens/Settings/Debug/Tabs/RenderDebugView.xaml b/src/Artemis.UI/Screens/Settings/Debug/Tabs/RenderDebugView.xaml
index 4e9519682..20ad8f5ad 100644
--- a/src/Artemis.UI/Screens/Settings/Debug/Tabs/RenderDebugView.xaml
+++ b/src/Artemis.UI/Screens/Settings/Debug/Tabs/RenderDebugView.xaml
@@ -27,10 +27,12 @@
This image shows what is being rendered and dispatched to RGB.NET
-
- FPS:
+
+
+
+
+
-
diff --git a/src/Artemis.UI/Screens/Settings/Debug/Tabs/RenderDebugViewModel.cs b/src/Artemis.UI/Screens/Settings/Debug/Tabs/RenderDebugViewModel.cs
index 2d5fc3572..7bfd7ef8d 100644
--- a/src/Artemis.UI/Screens/Settings/Debug/Tabs/RenderDebugViewModel.cs
+++ b/src/Artemis.UI/Screens/Settings/Debug/Tabs/RenderDebugViewModel.cs
@@ -15,6 +15,8 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
private readonly ICoreService _coreService;
private double _currentFps;
private ImageSource _currentFrame;
+ private int _renderWidth;
+ private int _renderHeight;
public RenderDebugViewModel(ICoreService coreService)
{
@@ -34,6 +36,18 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
set => SetAndNotify(ref _currentFps, value);
}
+ public int RenderWidth
+ {
+ get => _renderWidth;
+ set => SetAndNotify(ref _renderWidth, value);
+ }
+
+ public int RenderHeight
+ {
+ get => _renderHeight;
+ set => SetAndNotify(ref _renderHeight, value);
+ }
+
protected override void OnActivate()
{
_coreService.FrameRendered += CoreServiceOnFrameRendered;
@@ -56,6 +70,8 @@ namespace Artemis.UI.Screens.Settings.Debug.Tabs
return;
SKImageInfo bitmapInfo = e.Texture.Bitmap.Info;
+ RenderHeight = bitmapInfo.Height;
+ RenderWidth = bitmapInfo.Width;
if (!(CurrentFrame is WriteableBitmap writeableBitmap) ||
writeableBitmap.Width != bitmapInfo.Width ||
diff --git a/src/Artemis.UI/Screens/Settings/Device/DeviceLayoutDialogView.xaml b/src/Artemis.UI/Screens/Settings/Device/DeviceLayoutDialogView.xaml
new file mode 100644
index 000000000..90f9ae552
--- /dev/null
+++ b/src/Artemis.UI/Screens/Settings/Device/DeviceLayoutDialogView.xaml
@@ -0,0 +1,187 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Select a physical layout
+
+
+ Artemis couldn't automatically determine the physical layout of your .
+ In order for Artemis to know which keys are on your keyboard and where they're located, select the matching layout below.
+
+
+ P.S. Don't worry about missing special keys like num keys/function keys or macro keys, they aren't important here.
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Select a logical layout
+
+
+ Artemis couldn't automatically determine the logical layout of your .
+ While not as important as the physical layout, setting the correct logical layout will allow Artemis to show the right keycaps (if a matching layout file is present)
+
+
+
+
+
+
+
+
+ ()
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Settings/Device/DeviceLayoutDialogViewModel.cs b/src/Artemis.UI/Screens/Settings/Device/DeviceLayoutDialogViewModel.cs
new file mode 100644
index 000000000..50a996e56
--- /dev/null
+++ b/src/Artemis.UI/Screens/Settings/Device/DeviceLayoutDialogViewModel.cs
@@ -0,0 +1,125 @@
+using System;
+using System.Collections;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Threading.Tasks;
+using Artemis.Core;
+using Artemis.Core.Services;
+using Artemis.UI.Shared.Services;
+using MaterialDesignExtensions.Model;
+
+namespace Artemis.UI.Screens.Settings.Device
+{
+ public class DeviceLayoutDialogViewModel : DialogViewModelBase
+ {
+ private readonly IRgbService _rgbService;
+ private bool _selectPhysicalLayout;
+ private RegionInfoAutocompleteSource _autocompleteSource;
+ private RegionInfo _selectedRegion;
+
+ public DeviceLayoutDialogViewModel(ArtemisDevice device, IRgbService rgbService)
+ {
+ _rgbService = rgbService;
+ Device = device;
+ SelectPhysicalLayout = !device.DeviceProvider.CanDetectPhysicalLayout;
+
+ Task.Run(() =>
+ {
+ AutocompleteSource = new RegionInfoAutocompleteSource();
+ SelectedRegion = AutocompleteSource.Regions.FirstOrDefault(r => r.TwoLetterISORegionName == Device.LogicalLayout ||
+ r.TwoLetterISORegionName == "US" && Device.LogicalLayout == "NA");
+ });
+ }
+
+ public ArtemisDevice Device { get; }
+
+ public RegionInfoAutocompleteSource AutocompleteSource
+ {
+ get => _autocompleteSource;
+ set => SetAndNotify(ref _autocompleteSource, value);
+ }
+
+ public RegionInfo SelectedRegion
+ {
+ get => _selectedRegion;
+ set
+ {
+ SetAndNotify(ref _selectedRegion, value);
+ NotifyOfPropertyChange(nameof(CanConfirm));
+ }
+ }
+
+ public bool SelectPhysicalLayout
+ {
+ get => _selectPhysicalLayout;
+ set => SetAndNotify(ref _selectPhysicalLayout, value);
+ }
+
+ public bool CanConfirm => SelectedRegion != null;
+
+ public void ApplyPhysicalLayout(string physicalLayout)
+ {
+ Device.PhysicalLayout = Enum.Parse(physicalLayout);
+
+ _rgbService.SaveDevice(Device);
+ _rgbService.ApplyBestDeviceLayout(Device);
+
+ SelectPhysicalLayout = false;
+ }
+
+ private void ApplyLogicalLayout(string logicalLayout)
+ {
+ Device.LogicalLayout = logicalLayout;
+
+ _rgbService.SaveDevice(Device);
+ _rgbService.ApplyBestDeviceLayout(Device);
+ }
+
+ public void Confirm()
+ {
+ if (!CanConfirm || Session == null || Session.IsEnded)
+ return;
+
+ ApplyLogicalLayout(SelectedRegion.TwoLetterISORegionName);
+ Session?.Close(true);
+ }
+ }
+
+ public class RegionInfoAutocompleteSource : IAutocompleteSource
+ {
+ public List Regions { get; set; }
+
+ public RegionInfoAutocompleteSource()
+ {
+ Regions = CultureInfo.GetCultures(CultureTypes.SpecificCultures).ToList()
+ .Select(c => new RegionInfo(c.LCID))
+ .GroupBy(r => r.EnglishName)
+ .Select(g => g.First())
+ .OrderBy(r => r.EnglishName)
+ .ToList();
+ }
+
+ IEnumerable IAutocompleteSource.Search(string searchTerm)
+ {
+ if (searchTerm == null)
+ return Regions;
+
+ searchTerm = searchTerm.ToLower();
+ return Regions.Where(r => r.EnglishName.ToLower().Contains(searchTerm) ||
+ r.NativeName.ToLower().Contains(searchTerm) ||
+ r.TwoLetterISORegionName.ToLower().Contains(searchTerm));
+ }
+
+ public IEnumerable Search(string searchTerm)
+ {
+ if (searchTerm == null)
+ return Regions;
+
+ searchTerm = searchTerm.ToLower();
+ return Regions.Where(r => r.EnglishName.ToLower().Contains(searchTerm) ||
+ r.NativeName.ToLower().Contains(searchTerm) ||
+ r.TwoLetterISORegionName.ToLower().Contains(searchTerm));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Settings/Device/Tabs/DeviceInfoTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Device/Tabs/DeviceInfoTabViewModel.cs
index dcd976f96..e386b676a 100644
--- a/src/Artemis.UI/Screens/Settings/Device/Tabs/DeviceInfoTabViewModel.cs
+++ b/src/Artemis.UI/Screens/Settings/Device/Tabs/DeviceInfoTabViewModel.cs
@@ -12,7 +12,7 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs
DisplayName = "INFO";
}
- public bool IsKeyboard => Device.RgbDevice is IKeyboard;
+ public bool IsKeyboard => Device.RgbDevice.DeviceInfo.DeviceType == RGBDeviceType.Keyboard;
public ArtemisDevice Device { get; }
}
}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Settings/Device/Tabs/DevicePropertiesTabView.xaml b/src/Artemis.UI/Screens/Settings/Device/Tabs/DevicePropertiesTabView.xaml
index 56da0c5bd..b6e4afd4e 100644
--- a/src/Artemis.UI/Screens/Settings/Device/Tabs/DevicePropertiesTabView.xaml
+++ b/src/Artemis.UI/Screens/Settings/Device/Tabs/DevicePropertiesTabView.xaml
@@ -174,6 +174,10 @@
+
+
diff --git a/src/Artemis.UI/Screens/Settings/Device/Tabs/DevicePropertiesTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Device/Tabs/DevicePropertiesTabViewModel.cs
index 4de139698..19f425e70 100644
--- a/src/Artemis.UI/Screens/Settings/Device/Tabs/DevicePropertiesTabViewModel.cs
+++ b/src/Artemis.UI/Screens/Settings/Device/Tabs/DevicePropertiesTabViewModel.cs
@@ -1,4 +1,5 @@
-using System.ComponentModel;
+using System.Collections.Generic;
+using System.ComponentModel;
using System.Threading.Tasks;
using System.Windows.Controls;
using System.Windows.Input;
@@ -15,6 +16,7 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs
{
private readonly ICoreService _coreService;
private readonly IMessageService _messageService;
+ private readonly IDialogService _dialogService;
private readonly IRgbService _rgbService;
private float _blueScale;
private SKColor _currentColor;
@@ -33,11 +35,13 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs
ICoreService coreService,
IRgbService rgbService,
IMessageService messageService,
+ IDialogService dialogService,
IModelValidator validator) : base(validator)
{
_coreService = coreService;
_rgbService = rgbService;
_messageService = messageService;
+ _dialogService = dialogService;
Device = device;
DisplayName = "PROPERTIES";
@@ -126,6 +130,11 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs
}
}
+ public async Task SelectPhysicalLayout()
+ {
+ await _dialogService.ShowDialog(new Dictionary {{"device", Device}});
+ }
+
public async Task Apply()
{
await ValidateAsync();
@@ -167,12 +176,21 @@ namespace Artemis.UI.Screens.Settings.Device.Tabs
_initialGreenScale = Device.GreenScale;
_initialBlueScale = Device.BlueScale;
CurrentColor = SKColors.White;
+
_coreService.FrameRendering += OnFrameRendering;
Device.PropertyChanged += DeviceOnPropertyChanged;
base.OnActivate();
}
+ protected override void OnDeactivate()
+ {
+ _coreService.FrameRendering -= OnFrameRendering;
+ Device.PropertyChanged -= DeviceOnPropertyChanged;
+
+ base.OnDeactivate();
+ }
+
#region Event handlers
private void DeviceOnPropertyChanged(object sender, PropertyChangedEventArgs e)
diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsTabViewModel.cs
index 6c13a7266..e3cb174a6 100644
--- a/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsTabViewModel.cs
+++ b/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsTabViewModel.cs
@@ -24,12 +24,11 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices
_settingsVmFactory = settingsVmFactory;
}
- protected override void OnActivate()
+ protected override void OnInitialActivate()
{
// Take it off the UI thread to avoid freezing on tab change
Task.Run(async () =>
{
- Items.Clear();
await Task.Delay(200);
List instances = _rgbService.Devices.Select(d => _settingsVmFactory.CreateDeviceSettingsViewModel(d)).ToList();
@@ -37,7 +36,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices
Items.Add(deviceSettingsViewModel);
});
- base.OnActivate();
+ base.OnInitialActivate();
}
public async Task ShowDeviceDisableDialog()
diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsViewModel.cs
index c8cb5d0cd..2005b6753 100644
--- a/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsViewModel.cs
+++ b/src/Artemis.UI/Screens/Settings/Tabs/Devices/DeviceSettingsViewModel.cs
@@ -84,7 +84,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices
public void ViewProperties()
{
- _windowManager.ShowDialog(_deviceDebugVmFactory.DeviceDialogViewModel(Device));
+ _windowManager.ShowWindow(_deviceDebugVmFactory.DeviceDialogViewModel(Device));
}
private async Task UpdateIsDeviceEnabled(bool value)
{
diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginFeatureView.xaml b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginFeatureView.xaml
index eb8f06d5f..bd8bc03ff 100644
--- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginFeatureView.xaml
+++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginFeatureView.xaml
@@ -27,13 +27,13 @@
Width="20"
VerticalAlignment="Center"
HorizontalAlignment="Center"
- Visibility="{Binding LoadException, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}" />
+ Visibility="{Binding LoadException, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted, FallbackValue=Collapsed}" />
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsTabViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsTabViewModel.cs
index 787ab9c83..fa9632187 100644
--- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsTabViewModel.cs
+++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsTabViewModel.cs
@@ -4,6 +4,7 @@ using System.Linq;
using System.Threading.Tasks;
using Artemis.Core;
using Artemis.Core.Services;
+using Artemis.UI.Extensions;
using Artemis.UI.Ninject.Factories;
using Artemis.UI.Shared.Services;
using Ookii.Dialogs.Wpf;
@@ -43,26 +44,36 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
if (_instances == null)
return;
- Items.Clear();
+ List instances = _instances;
+ string search = SearchPluginInput?.ToLower();
+ if (!string.IsNullOrWhiteSpace(search))
+ instances = instances.Where(i => i.Plugin.Info.Name.ToLower().Contains(search) ||
+ i.Plugin.Info.Description != null && i.Plugin.Info.Description.ToLower().Contains(search)).ToList();
- if (string.IsNullOrWhiteSpace(SearchPluginInput))
- Items.AddRange(_instances);
- else
- Items.AddRange(_instances.Where(i => i.Plugin.Info.Name.Contains(SearchPluginInput, StringComparison.OrdinalIgnoreCase) ||
- i.Plugin.Info.Description.Contains(SearchPluginInput, StringComparison.OrdinalIgnoreCase)));
+ foreach (PluginSettingsViewModel pluginSettingsViewModel in instances)
+ {
+ if (!Items.Contains(pluginSettingsViewModel))
+ Items.Add(pluginSettingsViewModel);
+ }
+ foreach (PluginSettingsViewModel pluginSettingsViewModel in Items.ToList())
+ {
+ if (!instances.Contains(pluginSettingsViewModel))
+ Items.Remove(pluginSettingsViewModel);
+ }
+
+ ((BindableCollection) Items).Sort(i => i.Plugin.Info.Name);
}
- protected override void OnActivate()
+ protected override void OnInitialActivate()
{
// Take it off the UI thread to avoid freezing on tab change
Task.Run(async () =>
{
- Items.Clear();
await Task.Delay(200);
GetPluginInstances();
});
- base.OnActivate();
+ base.OnInitialActivate();
}
public void ImportPlugin()
diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsView.xaml b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsView.xaml
index 34f106e9f..746ef06fc 100644
--- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsView.xaml
+++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsView.xaml
@@ -8,6 +8,7 @@
xmlns:devices="clr-namespace:Artemis.UI.Screens.Settings.Tabs.Plugins"
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
+ xmlns:behaviors="clr-namespace:Artemis.UI.Behaviors"
d:DataContext="{d:DesignInstance devices:PluginSettingsViewModel}"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
@@ -34,20 +35,27 @@
+ Width="48"
+ Height="48"
+ Margin="0 5 0 0"
+ Grid.Row="0"
+ Grid.RowSpan="2"
+ HorizontalAlignment="Center"
+ VerticalAlignment="Top" />
-
+
@@ -55,9 +63,9 @@
-
-
-
+
Plugin enabled
-
+ Visibility="{Binding Plugin.Info.RequiresAdmin, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
@@ -128,7 +136,7 @@
-
+
diff --git a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs
index 06fa111be..f8394b325 100644
--- a/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs
+++ b/src/Artemis.UI/Screens/Settings/Tabs/Plugins/PluginSettingsViewModel.cs
@@ -76,7 +76,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
try
{
PluginConfigurationViewModel viewModel = (PluginConfigurationViewModel) Plugin.Kernel.Get(configurationViewModel.Type);
- _windowManager.ShowDialog(new PluginSettingsWindowViewModel(viewModel, Icon));
+ _windowManager.ShowWindow(new PluginSettingsWindowViewModel(viewModel, Icon));
}
catch (Exception e)
{
diff --git a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs
index 1700dc144..917024ec6 100644
--- a/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs
+++ b/src/Artemis.UI/Screens/SurfaceEditor/SurfaceEditorViewModel.cs
@@ -241,7 +241,7 @@ namespace Artemis.UI.Screens.SurfaceEditor
public void ViewProperties(ArtemisDevice device)
{
- _windowManager.ShowDialog(_deviceDebugVmFactory.DeviceDialogViewModel(device));
+ _windowManager.ShowWindow(_deviceDebugVmFactory.DeviceDialogViewModel(device));
}
public async Task DetectInput(ArtemisDevice device)
diff --git a/src/Artemis.UI/Services/DeviceLayoutService.cs b/src/Artemis.UI/Services/DeviceLayoutService.cs
new file mode 100644
index 000000000..dd7a6a83d
--- /dev/null
+++ b/src/Artemis.UI/Services/DeviceLayoutService.cs
@@ -0,0 +1,89 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Threading.Tasks;
+using Artemis.Core;
+using Artemis.Core.Services;
+using Artemis.UI.Screens.Settings.Device;
+using Artemis.UI.Shared.Services;
+using MaterialDesignThemes.Wpf;
+using RGB.NET.Core;
+using KeyboardLayoutType = Artemis.Core.KeyboardLayoutType;
+
+namespace Artemis.UI.Services
+{
+ public class DeviceLayoutService : IDeviceLayoutService
+ {
+ private readonly IDialogService _dialogService;
+ private readonly List _ignoredDevices;
+ private readonly IMessageService _messageService;
+ private readonly IRgbService _rgbService;
+ private readonly IWindowService _windowService;
+
+ public DeviceLayoutService(IDialogService dialogService, IRgbService rgbService, IWindowService windowService, IMessageService messageService)
+ {
+ _dialogService = dialogService;
+ _rgbService = rgbService;
+ _windowService = windowService;
+ _messageService = messageService;
+ _ignoredDevices = new List();
+
+ rgbService.DeviceAdded += RgbServiceOnDeviceAdded;
+ windowService.MainWindowOpened += WindowServiceOnMainWindowOpened;
+ }
+
+ private async Task RequestLayoutInput(ArtemisDevice artemisDevice)
+ {
+ bool configure = await _dialogService.ShowConfirmDialog(
+ "Device requires layout info",
+ $"Artemis could not detect the layout of your {artemisDevice.RgbDevice.DeviceInfo.DeviceName}. Please configure out manually",
+ "Configure",
+ "Ignore for now"
+ );
+
+ if (!configure)
+ {
+ _ignoredDevices.Add(artemisDevice);
+ return;
+ }
+
+ await _dialogService.ShowDialog(new Dictionary {{"device", artemisDevice}});
+ }
+
+ private bool DeviceNeedsLayout(ArtemisDevice d)
+ {
+ return d.RgbDevice.DeviceInfo.DeviceType == RGBDeviceType.Keyboard &&
+ (d.LogicalLayout == null || d.PhysicalLayout == KeyboardLayoutType.Unknown) &&
+ (!d.DeviceProvider.CanDetectLogicalLayout || !d.DeviceProvider.CanDetectPhysicalLayout);
+ }
+
+ #region Event handlers
+
+ private async void WindowServiceOnMainWindowOpened(object? sender, EventArgs e)
+ {
+ List devices = _rgbService.Devices.Where(device => DeviceNeedsLayout(device) && !_ignoredDevices.Contains(device)).ToList();
+ foreach (ArtemisDevice artemisDevice in devices)
+ await RequestLayoutInput(artemisDevice);
+ }
+
+ private async void RgbServiceOnDeviceAdded(object sender, DeviceEventArgs e)
+ {
+ if (_ignoredDevices.Contains(e.Device) || !DeviceNeedsLayout(e.Device))
+ return;
+
+ if (!_windowService.IsMainWindowOpen)
+ {
+ _messageService.ShowNotification("New device detected", "Detected a new device that needs layout setup", PackIconKind.Keyboard);
+ return;
+ }
+
+ await RequestLayoutInput(e.Device);
+ }
+
+ #endregion
+ }
+
+ public interface IDeviceLayoutService : IArtemisUIService
+ {
+ }
+}
\ No newline at end of file