mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Devices - Added keyboard layout selection logic
UI - Improved plugin settings tab performance, added search text highlighting
This commit is contained in:
parent
46d3a288e9
commit
b209bfd833
@ -287,7 +287,7 @@ namespace Artemis.Core
|
|||||||
if (!Enabled || Path == null || LayerShape?.Path == null || !General.PropertiesInitialized || !Transform.PropertiesInitialized)
|
if (!Enabled || Path == null || LayerShape?.Path == null || !General.PropertiesInitialized || !Transform.PropertiesInitialized)
|
||||||
return;
|
return;
|
||||||
// Ensure the brush is ready
|
// Ensure the brush is ready
|
||||||
if (LayerBrush?.BaseProperties?.PropertiesInitialized == false)
|
if (LayerBrush == null || LayerBrush?.BaseProperties?.PropertiesInitialized == false)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
RenderTimeline(Timeline, canvas);
|
RenderTimeline(Timeline, canvas);
|
||||||
|
|||||||
@ -391,12 +391,16 @@ namespace Artemis.Core
|
|||||||
if (RgbDevice.DeviceInfo.DeviceType != RGBDeviceType.Keyboard)
|
if (RgbDevice.DeviceInfo.DeviceType != RGBDeviceType.Keyboard)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
IKeyboard keyboard = (IKeyboard) RgbDevice;
|
IKeyboard? keyboard = RgbDevice as IKeyboard;
|
||||||
// If supported, detect the device layout so that we can load the correct one
|
// If supported, detect the device layout so that we can load the correct one
|
||||||
if (DeviceProvider.CanDetectLogicalLayout)
|
if (DeviceProvider.CanDetectPhysicalLayout && keyboard != null)
|
||||||
LogicalLayout = DeviceProvider.GetLogicalLayout(keyboard);
|
|
||||||
if (DeviceProvider.CanDetectPhysicalLayout)
|
|
||||||
PhysicalLayout = (KeyboardLayoutType) keyboard.DeviceInfo.Layout;
|
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
|
#region Events
|
||||||
|
|||||||
@ -288,12 +288,12 @@ namespace Artemis.UI.Shared
|
|||||||
|
|
||||||
private void DeviceUpdated(object? sender, EventArgs e)
|
private void DeviceUpdated(object? sender, EventArgs e)
|
||||||
{
|
{
|
||||||
SetupForDevice();
|
Execute.PostToUIThread(SetupForDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void DevicePropertyChanged(object? sender, PropertyChangedEventArgs e)
|
private void DevicePropertyChanged(object? sender, PropertyChangedEventArgs e)
|
||||||
{
|
{
|
||||||
SetupForDevice();
|
Execute.PostToUIThread(SetupForDevice);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Render()
|
private void Render()
|
||||||
|
|||||||
@ -17,7 +17,7 @@
|
|||||||
Text="{Binding Text}"
|
Text="{Binding Text}"
|
||||||
TextWrapping="Wrap" />
|
TextWrapping="Wrap" />
|
||||||
|
|
||||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="16">
|
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0 8 0 0">
|
||||||
<Button Style="{StaticResource MaterialDesignFlatButton}"
|
<Button Style="{StaticResource MaterialDesignFlatButton}"
|
||||||
Focusable="False"
|
Focusable="False"
|
||||||
IsCancel="True"
|
IsCancel="True"
|
||||||
|
|||||||
169
src/Artemis.UI/Behaviors/HighlightTermBehavior.cs
Normal file
169
src/Artemis.UI/Behaviors/HighlightTermBehavior.cs
Normal file
@ -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<string> SplitTextIntoTermAndNotTermParts(string text, string term)
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(text))
|
||||||
|
return new List<string> {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<string> 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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -90,6 +90,9 @@ namespace Artemis.UI
|
|||||||
IRegistrationService registrationService = Kernel.Get<IRegistrationService>();
|
IRegistrationService registrationService = Kernel.Get<IRegistrationService>();
|
||||||
registrationService.RegisterInputProvider();
|
registrationService.RegisterInputProvider();
|
||||||
registrationService.RegisterControllers();
|
registrationService.RegisterControllers();
|
||||||
|
|
||||||
|
// Initialize background services
|
||||||
|
Kernel.Get<IDeviceLayoutService>();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void ConfigureIoC(IKernel kernel)
|
protected override void ConfigureIoC(IKernel kernel)
|
||||||
|
|||||||
@ -24,12 +24,11 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices
|
|||||||
_settingsVmFactory = settingsVmFactory;
|
_settingsVmFactory = settingsVmFactory;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnActivate()
|
protected override void OnInitialActivate()
|
||||||
{
|
{
|
||||||
// Take it off the UI thread to avoid freezing on tab change
|
// Take it off the UI thread to avoid freezing on tab change
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
Items.Clear();
|
|
||||||
await Task.Delay(200);
|
await Task.Delay(200);
|
||||||
|
|
||||||
List<DeviceSettingsViewModel> instances = _rgbService.Devices.Select(d => _settingsVmFactory.CreateDeviceSettingsViewModel(d)).ToList();
|
List<DeviceSettingsViewModel> instances = _rgbService.Devices.Select(d => _settingsVmFactory.CreateDeviceSettingsViewModel(d)).ToList();
|
||||||
@ -37,7 +36,7 @@ namespace Artemis.UI.Screens.Settings.Tabs.Devices
|
|||||||
Items.Add(deviceSettingsViewModel);
|
Items.Add(deviceSettingsViewModel);
|
||||||
});
|
});
|
||||||
|
|
||||||
base.OnActivate();
|
base.OnInitialActivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public async Task<bool> ShowDeviceDisableDialog()
|
public async Task<bool> ShowDeviceDisableDialog()
|
||||||
|
|||||||
@ -27,13 +27,13 @@
|
|||||||
Width="20"
|
Width="20"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
Visibility="{Binding LoadException, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted}" />
|
Visibility="{Binding LoadException, Converter={StaticResource NullToVisibilityConverter}, ConverterParameter=Inverted, FallbackValue=Collapsed}" />
|
||||||
|
|
||||||
<Button Grid.Column="0"
|
<Button Grid.Column="0"
|
||||||
Margin="-8"
|
Margin="-8"
|
||||||
VerticalAlignment="Center"
|
VerticalAlignment="Center"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
Visibility="{Binding LoadException, Converter={StaticResource NullToVisibilityConverter}}"
|
Visibility="{Binding LoadException, Converter={StaticResource NullToVisibilityConverter}, FallbackValue=Collapsed}"
|
||||||
Style="{StaticResource MaterialDesignIconButton}"
|
Style="{StaticResource MaterialDesignIconButton}"
|
||||||
Foreground="#E74C4C"
|
Foreground="#E74C4C"
|
||||||
ToolTip="An exception occurred while enabling this feature, click to view"
|
ToolTip="An exception occurred while enabling this feature, click to view"
|
||||||
@ -46,13 +46,13 @@
|
|||||||
|
|
||||||
<!-- Enable toggle column -->
|
<!-- Enable toggle column -->
|
||||||
<StackPanel Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="8"
|
<StackPanel Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="8"
|
||||||
Visibility="{Binding Enabling, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}">
|
Visibility="{Binding Enabling, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay, FallbackValue=Collapsed}">
|
||||||
<CheckBox Style="{StaticResource MaterialDesignCheckBox}" IsChecked="{Binding IsEnabled}">
|
<CheckBox Style="{StaticResource MaterialDesignCheckBox}" IsChecked="{Binding IsEnabled}">
|
||||||
Feature enabled
|
Feature enabled
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
<StackPanel Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="7"
|
<StackPanel Grid.Column="2" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="7"
|
||||||
Visibility="{Binding Enabling, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}">
|
Visibility="{Binding Enabling, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay, FallbackValue=Collapsed}">
|
||||||
<ProgressBar Style="{StaticResource MaterialDesignCircularProgressBar}" Value="0" IsIndeterminate="True" />
|
<ProgressBar Style="{StaticResource MaterialDesignCircularProgressBar}" Value="0" IsIndeterminate="True" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
|
|
||||||
|
|||||||
@ -65,18 +65,20 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
|||||||
|
|
||||||
protected override void OnInitialActivate()
|
protected override void OnInitialActivate()
|
||||||
{
|
{
|
||||||
base.OnInitialActivate();
|
|
||||||
_pluginManagementService.PluginFeatureEnabling += OnFeatureEnabling;
|
_pluginManagementService.PluginFeatureEnabling += OnFeatureEnabling;
|
||||||
_pluginManagementService.PluginFeatureEnabled += OnFeatureEnableStopped;
|
_pluginManagementService.PluginFeatureEnabled += OnFeatureEnableStopped;
|
||||||
_pluginManagementService.PluginFeatureEnableFailed += OnFeatureEnableStopped;
|
_pluginManagementService.PluginFeatureEnableFailed += OnFeatureEnableStopped;
|
||||||
|
|
||||||
|
base.OnInitialActivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void OnClose()
|
protected override void OnClose()
|
||||||
{
|
{
|
||||||
base.OnClose();
|
|
||||||
_pluginManagementService.PluginFeatureEnabling -= OnFeatureEnabling;
|
_pluginManagementService.PluginFeatureEnabling -= OnFeatureEnabling;
|
||||||
_pluginManagementService.PluginFeatureEnabled -= OnFeatureEnableStopped;
|
_pluginManagementService.PluginFeatureEnabled -= OnFeatureEnableStopped;
|
||||||
_pluginManagementService.PluginFeatureEnableFailed -= OnFeatureEnableStopped;
|
_pluginManagementService.PluginFeatureEnableFailed -= OnFeatureEnableStopped;
|
||||||
|
|
||||||
|
base.OnClose();
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task UpdateEnabled(bool enable)
|
private async Task UpdateEnabled(bool enable)
|
||||||
|
|||||||
@ -14,7 +14,7 @@
|
|||||||
<RowDefinition Height="Auto" />
|
<RowDefinition Height="Auto" />
|
||||||
<RowDefinition Height="*" />
|
<RowDefinition Height="*" />
|
||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
<Grid Margin="0 15" MinWidth="810" Width="{Binding Path=ActualWidth, ElementName=PluginsContainer}">
|
<Grid Margin="0 15" Width="810">
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
<ColumnDefinition Width="Auto" />
|
<ColumnDefinition Width="Auto" />
|
||||||
@ -41,21 +41,36 @@
|
|||||||
IMPORT PLUGIN
|
IMPORT PLUGIN
|
||||||
</Button>
|
</Button>
|
||||||
</Grid>
|
</Grid>
|
||||||
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
|
||||||
<ItemsControl ItemsSource="{Binding Items}" Margin="15 0 15 15" HorizontalAlignment="Center" MaxWidth="1700" x:Name="PluginsContainer">
|
|
||||||
<ItemsControl.ItemsPanel>
|
|
||||||
<ItemsPanelTemplate>
|
|
||||||
<WrapPanel />
|
|
||||||
</ItemsPanelTemplate>
|
|
||||||
</ItemsControl.ItemsPanel>
|
|
||||||
<ItemsControl.ItemTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<ContentControl s:View.Model="{Binding IsAsync=True}" Margin="5" HorizontalAlignment="Left" VerticalAlignment="Top" />
|
|
||||||
</DataTemplate>
|
|
||||||
</ItemsControl.ItemTemplate>
|
|
||||||
</ItemsControl>
|
|
||||||
|
|
||||||
</ScrollViewer>
|
<ListBox Grid.Row="1"
|
||||||
|
ItemsSource="{Binding Items}"
|
||||||
|
materialDesign:RippleAssist.IsDisabled="True"
|
||||||
|
VirtualizingPanel.ScrollUnit="Pixel"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
|
HorizontalContentAlignment="Center"
|
||||||
|
Margin="15 0 15 15">
|
||||||
|
<ListBox.ItemTemplate>
|
||||||
|
<DataTemplate>
|
||||||
|
<ContentControl s:View.Model="{Binding IsAsync=True}" Margin="5" HorizontalAlignment="Center" IsTabStop="False" />
|
||||||
|
</DataTemplate>
|
||||||
|
</ListBox.ItemTemplate>
|
||||||
|
<ListBox.ItemsPanel>
|
||||||
|
<ItemsPanelTemplate>
|
||||||
|
<VirtualizingStackPanel />
|
||||||
|
</ItemsPanelTemplate>
|
||||||
|
</ListBox.ItemsPanel>
|
||||||
|
|
||||||
|
<ListBox.ItemContainerStyle>
|
||||||
|
<Style TargetType="{x:Type ListBoxItem}">
|
||||||
|
<Setter Property="Template">
|
||||||
|
<Setter.Value>
|
||||||
|
<ControlTemplate TargetType="{x:Type ListBoxItem}">
|
||||||
|
<ContentPresenter />
|
||||||
|
</ControlTemplate>
|
||||||
|
</Setter.Value>
|
||||||
|
</Setter>
|
||||||
|
</Style>
|
||||||
|
</ListBox.ItemContainerStyle>
|
||||||
|
</ListBox>
|
||||||
</Grid>
|
</Grid>
|
||||||
|
|
||||||
</UserControl>
|
</UserControl>
|
||||||
@ -4,6 +4,7 @@ using System.Linq;
|
|||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
|
using Artemis.UI.Extensions;
|
||||||
using Artemis.UI.Ninject.Factories;
|
using Artemis.UI.Ninject.Factories;
|
||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using Ookii.Dialogs.Wpf;
|
using Ookii.Dialogs.Wpf;
|
||||||
@ -43,26 +44,36 @@ namespace Artemis.UI.Screens.Settings.Tabs.Plugins
|
|||||||
if (_instances == null)
|
if (_instances == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Items.Clear();
|
List<PluginSettingsViewModel> 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))
|
foreach (PluginSettingsViewModel pluginSettingsViewModel in instances)
|
||||||
Items.AddRange(_instances);
|
{
|
||||||
else
|
if (!Items.Contains(pluginSettingsViewModel))
|
||||||
Items.AddRange(_instances.Where(i => i.Plugin.Info.Name.Contains(SearchPluginInput, StringComparison.OrdinalIgnoreCase) ||
|
Items.Add(pluginSettingsViewModel);
|
||||||
i.Plugin.Info.Description.Contains(SearchPluginInput, StringComparison.OrdinalIgnoreCase)));
|
}
|
||||||
|
foreach (PluginSettingsViewModel pluginSettingsViewModel in Items.ToList())
|
||||||
|
{
|
||||||
|
if (!instances.Contains(pluginSettingsViewModel))
|
||||||
|
Items.Remove(pluginSettingsViewModel);
|
||||||
|
}
|
||||||
|
|
||||||
|
((BindableCollection<PluginSettingsViewModel>) 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
|
// Take it off the UI thread to avoid freezing on tab change
|
||||||
Task.Run(async () =>
|
Task.Run(async () =>
|
||||||
{
|
{
|
||||||
Items.Clear();
|
|
||||||
await Task.Delay(200);
|
await Task.Delay(200);
|
||||||
GetPluginInstances();
|
GetPluginInstances();
|
||||||
});
|
});
|
||||||
|
|
||||||
base.OnActivate();
|
base.OnInitialActivate();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void ImportPlugin()
|
public void ImportPlugin()
|
||||||
|
|||||||
@ -8,6 +8,7 @@
|
|||||||
xmlns:devices="clr-namespace:Artemis.UI.Screens.Settings.Tabs.Plugins"
|
xmlns:devices="clr-namespace:Artemis.UI.Screens.Settings.Tabs.Plugins"
|
||||||
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
|
xmlns:b="http://schemas.microsoft.com/xaml/behaviors"
|
||||||
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
xmlns:shared="clr-namespace:Artemis.UI.Shared;assembly=Artemis.UI.Shared"
|
||||||
|
xmlns:behaviors="clr-namespace:Artemis.UI.Behaviors"
|
||||||
d:DataContext="{d:DesignInstance devices:PluginSettingsViewModel}"
|
d:DataContext="{d:DesignInstance devices:PluginSettingsViewModel}"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
d:DesignHeight="450" d:DesignWidth="800">
|
d:DesignHeight="450" d:DesignWidth="800">
|
||||||
@ -34,20 +35,27 @@
|
|||||||
</Grid.RowDefinitions>
|
</Grid.RowDefinitions>
|
||||||
|
|
||||||
<shared:ArtemisIcon Icon="{Binding Icon}"
|
<shared:ArtemisIcon Icon="{Binding Icon}"
|
||||||
Width="48"
|
Width="48"
|
||||||
Height="48"
|
Height="48"
|
||||||
Margin="0 5 0 0"
|
Margin="0 5 0 0"
|
||||||
Grid.Row="0"
|
Grid.Row="0"
|
||||||
Grid.RowSpan="2"
|
Grid.RowSpan="2"
|
||||||
HorizontalAlignment="Center"
|
HorizontalAlignment="Center"
|
||||||
VerticalAlignment="Top" />
|
VerticalAlignment="Top" />
|
||||||
|
|
||||||
<TextBlock Grid.Column="1" Grid.Row="0" Style="{StaticResource MaterialDesignBody2TextBlock}" Text="{Binding Plugin.Info.Name}" />
|
<TextBlock Grid.Column="1" Grid.Row="0" Style="{StaticResource MaterialDesignBody2TextBlock}"
|
||||||
|
behaviors:HighlightTermBehavior.TermToBeHighlighted="{Binding Parent.SearchPluginInput}"
|
||||||
|
behaviors:HighlightTermBehavior.Text="{Binding Plugin.Info.Name}"
|
||||||
|
behaviors:HighlightTermBehavior.HighlightForeground="{StaticResource Primary600Foreground}"
|
||||||
|
behaviors:HighlightTermBehavior.HighlightBackground="{StaticResource Primary600}"/>
|
||||||
|
|
||||||
<TextBlock Grid.Column="1"
|
<TextBlock Grid.Column="1"
|
||||||
Grid.Row="1"
|
Grid.Row="1"
|
||||||
TextWrapping="Wrap"
|
TextWrapping="Wrap"
|
||||||
Text="{Binding Plugin.Info.Description}"
|
behaviors:HighlightTermBehavior.TermToBeHighlighted="{Binding Parent.SearchPluginInput}"
|
||||||
|
behaviors:HighlightTermBehavior.Text="{Binding Plugin.Info.Description}"
|
||||||
|
behaviors:HighlightTermBehavior.HighlightForeground="{StaticResource Primary600Foreground}"
|
||||||
|
behaviors:HighlightTermBehavior.HighlightBackground="{StaticResource Primary600}"
|
||||||
Style="{StaticResource MaterialDesignTextBlock}"
|
Style="{StaticResource MaterialDesignTextBlock}"
|
||||||
Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" />
|
Foreground="{DynamicResource MaterialDesignNavigationItemSubheader}" />
|
||||||
</Grid>
|
</Grid>
|
||||||
@ -88,7 +96,7 @@
|
|||||||
<materialDesign:PackIcon Kind="ShieldHalfFull"
|
<materialDesign:PackIcon Kind="ShieldHalfFull"
|
||||||
Margin="5 0 0 0"
|
Margin="5 0 0 0"
|
||||||
ToolTip="Plugin requires admin rights"
|
ToolTip="Plugin requires admin rights"
|
||||||
Visibility="{Binding Plugin.Info.RequiresAdmin, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}"/>
|
Visibility="{Binding Plugin.Info.RequiresAdmin, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Mode=OneWay}" />
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</CheckBox>
|
</CheckBox>
|
||||||
|
|
||||||
@ -128,7 +136,7 @@
|
|||||||
</b:Interaction.Behaviors>
|
</b:Interaction.Behaviors>
|
||||||
<ListBox.ItemTemplate>
|
<ListBox.ItemTemplate>
|
||||||
<DataTemplate>
|
<DataTemplate>
|
||||||
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
|
<ContentControl s:View.Model="{Binding IsAsync=True}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" IsTabStop="False" />
|
||||||
</DataTemplate>
|
</DataTemplate>
|
||||||
</ListBox.ItemTemplate>
|
</ListBox.ItemTemplate>
|
||||||
</ListBox>
|
</ListBox>
|
||||||
|
|||||||
@ -1,7 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Artemis.Core;
|
using Artemis.Core;
|
||||||
using Artemis.Core.Services;
|
using Artemis.Core.Services;
|
||||||
@ -9,7 +8,6 @@ using Artemis.UI.Screens.Settings.Device;
|
|||||||
using Artemis.UI.Shared.Services;
|
using Artemis.UI.Shared.Services;
|
||||||
using MaterialDesignThemes.Wpf;
|
using MaterialDesignThemes.Wpf;
|
||||||
using RGB.NET.Core;
|
using RGB.NET.Core;
|
||||||
using RGB.NET.Layout;
|
|
||||||
using KeyboardLayoutType = Artemis.Core.KeyboardLayoutType;
|
using KeyboardLayoutType = Artemis.Core.KeyboardLayoutType;
|
||||||
|
|
||||||
namespace Artemis.UI.Services
|
namespace Artemis.UI.Services
|
||||||
@ -17,10 +15,10 @@ namespace Artemis.UI.Services
|
|||||||
public class DeviceLayoutService : IDeviceLayoutService
|
public class DeviceLayoutService : IDeviceLayoutService
|
||||||
{
|
{
|
||||||
private readonly IDialogService _dialogService;
|
private readonly IDialogService _dialogService;
|
||||||
|
private readonly List<ArtemisDevice> _ignoredDevices;
|
||||||
|
private readonly IMessageService _messageService;
|
||||||
private readonly IRgbService _rgbService;
|
private readonly IRgbService _rgbService;
|
||||||
private readonly IWindowService _windowService;
|
private readonly IWindowService _windowService;
|
||||||
private readonly IMessageService _messageService;
|
|
||||||
private readonly List<ArtemisDevice> _ignoredDevices;
|
|
||||||
|
|
||||||
public DeviceLayoutService(IDialogService dialogService, IRgbService rgbService, IWindowService windowService, IMessageService messageService)
|
public DeviceLayoutService(IDialogService dialogService, IRgbService rgbService, IWindowService windowService, IMessageService messageService)
|
||||||
{
|
{
|
||||||
@ -31,34 +29,46 @@ namespace Artemis.UI.Services
|
|||||||
_ignoredDevices = new List<ArtemisDevice>();
|
_ignoredDevices = new List<ArtemisDevice>();
|
||||||
|
|
||||||
rgbService.DeviceAdded += RgbServiceOnDeviceAdded;
|
rgbService.DeviceAdded += RgbServiceOnDeviceAdded;
|
||||||
windowService.MainWindowOpened += async (_, _) => await RequestLayoutInput();
|
windowService.MainWindowOpened += WindowServiceOnMainWindowOpened;
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task RequestLayoutInput()
|
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<DeviceLayoutDialogViewModel>(new Dictionary<string, object> {{"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<ArtemisDevice> devices = _rgbService.Devices.Where(device => DeviceNeedsLayout(device) && !_ignoredDevices.Contains(device)).ToList();
|
List<ArtemisDevice> devices = _rgbService.Devices.Where(device => DeviceNeedsLayout(device) && !_ignoredDevices.Contains(device)).ToList();
|
||||||
foreach (ArtemisDevice artemisDevice in devices)
|
foreach (ArtemisDevice artemisDevice in devices)
|
||||||
{
|
await RequestLayoutInput(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);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
await _dialogService.ShowDialog<DeviceLayoutDialogViewModel>(new Dictionary<string, object> {{"device", artemisDevice}});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void RgbServiceOnDeviceAdded(object sender, DeviceEventArgs e)
|
private async void RgbServiceOnDeviceAdded(object sender, DeviceEventArgs e)
|
||||||
{
|
{
|
||||||
if (!DeviceNeedsLayout(e.Device))
|
if (_ignoredDevices.Contains(e.Device) || !DeviceNeedsLayout(e.Device))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!_windowService.IsMainWindowOpen)
|
if (!_windowService.IsMainWindowOpen)
|
||||||
@ -66,12 +76,11 @@ namespace Artemis.UI.Services
|
|||||||
_messageService.ShowNotification("New device detected", "Detected a new device that needs layout setup", PackIconKind.Keyboard);
|
_messageService.ShowNotification("New device detected", "Detected a new device that needs layout setup", PackIconKind.Keyboard);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await RequestLayoutInput(e.Device);
|
||||||
}
|
}
|
||||||
|
|
||||||
private bool DeviceNeedsLayout(ArtemisDevice d) => d.RgbDevice.DeviceInfo.DeviceType == RGBDeviceType.Keyboard &&
|
#endregion
|
||||||
d.LogicalLayout == null ||
|
|
||||||
d.PhysicalLayout == KeyboardLayoutType.Unknown &&
|
|
||||||
(!d.DeviceProvider.CanDetectLogicalLayout || !d.DeviceProvider.CanDetectPhysicalLayout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public interface IDeviceLayoutService : IArtemisUIService
|
public interface IDeviceLayoutService : IArtemisUIService
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user