diff --git a/src/Artemis.Core/Models/Profile/Layer.cs b/src/Artemis.Core/Models/Profile/Layer.cs
index 731969af2..ff30fffb9 100644
--- a/src/Artemis.Core/Models/Profile/Layer.cs
+++ b/src/Artemis.Core/Models/Profile/Layer.cs
@@ -67,35 +67,38 @@ namespace Artemis.Core.Models.Profile
if (RenderPath == null)
return;
- canvas.Save();
+ // TODO Just lock the whole thing, this is asking for deadlock
lock (_renderBitmap)
{
- foreach (var layerElement in LayerElements)
- layerElement.RenderPreProcess(surface, canvas);
-
- _renderCanvas.Clear();
- foreach (var layerElement in LayerElements)
- layerElement.Render(surface, _renderCanvas);
-
- var baseShader = SKShader.CreateBitmap(_renderBitmap, SKShaderTileMode.Repeat, SKShaderTileMode.Repeat, SKMatrix.MakeTranslation(RenderRectangle.Left, RenderRectangle.Top));
- foreach (var layerElement in LayerElements)
+ lock (LayerElements)
{
- var newBaseShader = layerElement.RenderPostProcess(surface, _renderBitmap, baseShader);
- if (newBaseShader == null)
- continue;
+ canvas.Save();
+ foreach (var layerElement in LayerElements)
+ layerElement.RenderPreProcess(surface, canvas);
- // Dispose the old base shader if the layer element provided a new one
- if (!ReferenceEquals(baseShader, newBaseShader))
- baseShader.Dispose();
+ _renderCanvas.Clear();
+ foreach (var layerElement in LayerElements)
+ layerElement.Render(surface, _renderCanvas);
- baseShader = newBaseShader;
+ var baseShader = SKShader.CreateBitmap(_renderBitmap, SKShaderTileMode.Repeat, SKShaderTileMode.Repeat, SKMatrix.MakeTranslation(RenderRectangle.Left, RenderRectangle.Top));
+ foreach (var layerElement in LayerElements)
+ {
+ var newBaseShader = layerElement.RenderPostProcess(surface, _renderBitmap, baseShader);
+ if (newBaseShader == null)
+ continue;
+
+ // Dispose the old base shader if the layer element provided a new one
+ if (!ReferenceEquals(baseShader, newBaseShader))
+ baseShader.Dispose();
+
+ baseShader = newBaseShader;
+ }
+
+ canvas.ClipPath(RenderPath);
+ canvas.DrawRect(RenderRectangle, new SKPaint {Shader = baseShader, FilterQuality = SKFilterQuality.Low});
+ baseShader.Dispose();
+ canvas.Restore();
}
-
- canvas.ClipPath(RenderPath);
- canvas.DrawRect(RenderRectangle, new SKPaint {Shader = baseShader, FilterQuality = SKFilterQuality.Low});
- baseShader.Dispose();
-
- canvas.Restore();
}
}
@@ -162,12 +165,18 @@ namespace Artemis.Core.Models.Profile
internal void AddLayerElement(LayerElement layerElement)
{
- _layerElements.Add(layerElement);
+ lock (LayerElements)
+ {
+ _layerElements.Add(layerElement);
+ }
}
internal void RemoveLayerElement(LayerElement layerElement)
{
- _layerElements.Remove(layerElement);
+ lock (LayerElements)
+ {
+ _layerElements.Remove(layerElement);
+ }
}
internal void PopulateLeds(ArtemisSurface surface)
diff --git a/src/Artemis.Core/Services/Storage/ProfileService.cs b/src/Artemis.Core/Services/Storage/ProfileService.cs
index 7a85598bb..e59d187ea 100644
--- a/src/Artemis.Core/Services/Storage/ProfileService.cs
+++ b/src/Artemis.Core/Services/Storage/ProfileService.cs
@@ -77,7 +77,8 @@ namespace Artemis.Core.Services.Storage
public void ActivateProfile(ProfileModule module, Profile profile)
{
module.ChangeActiveProfile(profile, _surfaceService.ActiveSurface);
- InstantiateProfileLayerElements(profile);
+ if (profile != null)
+ InstantiateProfileLayerElements(profile);
}
public void DeleteProfile(Profile profile)
diff --git a/src/Artemis.UI/Artemis.UI.csproj b/src/Artemis.UI/Artemis.UI.csproj
index 94e5414a0..b40eb1fab 100644
--- a/src/Artemis.UI/Artemis.UI.csproj
+++ b/src/Artemis.UI/Artemis.UI.csproj
@@ -139,6 +139,7 @@
+
..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll
@@ -170,6 +171,9 @@
Designer
+
+ ColorPickerView.xaml
+
@@ -177,11 +181,13 @@
+
+
@@ -247,6 +253,10 @@
Code
+
+ Designer
+ MSBuild:Compile
+
Designer
MSBuild:Compile
diff --git a/src/Artemis.UI/Controls/ColorPicker/ColorPickerView.xaml b/src/Artemis.UI/Controls/ColorPicker/ColorPickerView.xaml
new file mode 100644
index 000000000..88b805a2e
--- /dev/null
+++ b/src/Artemis.UI/Controls/ColorPicker/ColorPickerView.xaml
@@ -0,0 +1,13 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/src/Artemis.UI/Controls/ColorPicker/ColorPickerView.xaml.cs b/src/Artemis.UI/Controls/ColorPicker/ColorPickerView.xaml.cs
new file mode 100644
index 000000000..2bb475ecf
--- /dev/null
+++ b/src/Artemis.UI/Controls/ColorPicker/ColorPickerView.xaml.cs
@@ -0,0 +1,28 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace Artemis.UI.Controls.ColorPicker
+{
+ ///
+ /// Interaction logic for ColorPickerView.xaml
+ ///
+ public partial class ColorPickerView : UserControl
+ {
+ public ColorPickerView()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/src/Artemis.UI/Events/WindowsThemeEventArgs.cs b/src/Artemis.UI/Events/WindowsThemeEventArgs.cs
new file mode 100644
index 000000000..54310f545
--- /dev/null
+++ b/src/Artemis.UI/Events/WindowsThemeEventArgs.cs
@@ -0,0 +1,15 @@
+using System;
+using Artemis.UI.Utilities;
+
+namespace Artemis.UI.Events
+{
+ public class WindowsThemeEventArgs : EventArgs
+ {
+ public WindowsThemeEventArgs(ThemeWatcher.WindowsTheme theme)
+ {
+ Theme = theme;
+ }
+
+ public ThemeWatcher.WindowsTheme Theme { get; set; }
+ }
+}
\ No newline at end of file
diff --git a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileDeviceView.xaml b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileDeviceView.xaml
index af09e06c0..5fda64a2a 100644
--- a/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileDeviceView.xaml
+++ b/src/Artemis.UI/Screens/Module/ProfileEditor/Visualization/ProfileDeviceView.xaml
@@ -6,6 +6,7 @@
xmlns:s="https://github.com/canton7/Stylet"
xmlns:converters="clr-namespace:Artemis.UI.Converters"
xmlns:visualization="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.Visualization"
+ xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
d:DataContext="{d:DesignInstance {x:Type visualization:ProfileDeviceViewModel}}"
d:DesignHeight="450" d:DesignWidth="800">
@@ -20,7 +21,9 @@
-
+
+
+
-
+
@@ -60,10 +60,10 @@
-
+
-
-
+
+
diff --git a/src/Artemis.UI/Screens/RootView.xaml b/src/Artemis.UI/Screens/RootView.xaml
index bc2b0ca91..7a7f20721 100644
--- a/src/Artemis.UI/Screens/RootView.xaml
+++ b/src/Artemis.UI/Screens/RootView.xaml
@@ -12,7 +12,11 @@
Icon="/Artemis.UI;component/Resources/logo-512.png"
Title="Artemis"
GlowBrush="{DynamicResource AccentColorBrush}"
- FontFamily="{StaticResource DefaultFont}"
+ TextElement.Foreground="{DynamicResource MaterialDesignBody}"
+ Background="{DynamicResource MaterialDesignPaper}"
+ TextElement.FontWeight="Medium"
+ TextElement.FontSize="14"
+ FontFamily="pack://application:,,,/MaterialDesignThemes.Wpf;component/Resources/Roboto/#Roboto"
SaveWindowPosition="True"
UseLayoutRounding="True"
Deactivated="{s:Action WindowDeactivated}"
diff --git a/src/Artemis.UI/Screens/RootViewModel.cs b/src/Artemis.UI/Screens/RootViewModel.cs
index 368d4aa9a..bb3f6d05a 100644
--- a/src/Artemis.UI/Screens/RootViewModel.cs
+++ b/src/Artemis.UI/Screens/RootViewModel.cs
@@ -13,6 +13,8 @@ using Artemis.UI.Screens.News;
using Artemis.UI.Screens.Settings;
using Artemis.UI.Screens.SurfaceEditor;
using Artemis.UI.Screens.Workshop;
+using Artemis.UI.Utilities;
+using MaterialDesignThemes.Wpf;
using Stylet;
namespace Artemis.UI.Screens
@@ -47,6 +49,19 @@ namespace Artemis.UI.Screens
_pluginService.PluginDisabled += PluginServiceOnPluginDisabled;
PropertyChanged += OnSelectedModuleChanged;
PropertyChanged += OnSelectedPageChanged;
+
+ var themeWatcher = new ThemeWatcher();
+ themeWatcher.ThemeChanged += (sender, args) => ApplyWindowsTheme(args.Theme);
+ ApplyWindowsTheme(themeWatcher.GetWindowsTheme());
+ }
+
+ private void ApplyWindowsTheme(ThemeWatcher.WindowsTheme windowsTheme)
+ {
+ var paletteHelper = new PaletteHelper();
+ var theme = paletteHelper.GetTheme();
+
+ theme.SetBaseTheme(windowsTheme == ThemeWatcher.WindowsTheme.Dark ? Theme.Dark : Theme.Light);
+ paletteHelper.SetTheme(theme);
}
public IObservableCollection Modules { get; set; }
diff --git a/src/Artemis.UI/Screens/Workshop/WorkshopView.xaml b/src/Artemis.UI/Screens/Workshop/WorkshopView.xaml
index 5a6d3dbdf..076ee0c1a 100644
--- a/src/Artemis.UI/Screens/Workshop/WorkshopView.xaml
+++ b/src/Artemis.UI/Screens/Workshop/WorkshopView.xaml
@@ -8,6 +8,6 @@
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
- Work work!
+ Work work!
\ No newline at end of file
diff --git a/src/Artemis.UI/Utilities/ThemeWatcher.cs b/src/Artemis.UI/Utilities/ThemeWatcher.cs
new file mode 100644
index 000000000..fbf7db504
--- /dev/null
+++ b/src/Artemis.UI/Utilities/ThemeWatcher.cs
@@ -0,0 +1,76 @@
+using System;
+using System.Globalization;
+using System.Management;
+using System.Security.Principal;
+using Artemis.UI.Events;
+using Microsoft.Win32;
+
+namespace Artemis.UI.Utilities
+{
+ public class ThemeWatcher
+ {
+ public ThemeWatcher()
+ {
+ WatchTheme();
+ }
+
+ public enum WindowsTheme
+ {
+ Light,
+ Dark
+ }
+
+ private const string RegistryKeyPath = @"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize";
+
+ private const string RegistryValueName = "AppsUseLightTheme";
+
+ public void WatchTheme()
+ {
+ var currentUser = WindowsIdentity.GetCurrent();
+ var query = string.Format(
+ CultureInfo.InvariantCulture,
+ @"SELECT * FROM RegistryValueChangeEvent WHERE Hive = 'HKEY_USERS' AND KeyPath = '{0}\\{1}' AND ValueName = '{2}'",
+ currentUser.User.Value,
+ RegistryKeyPath.Replace(@"\", @"\\"),
+ RegistryValueName);
+
+ try
+ {
+ var watcher = new ManagementEventWatcher(query);
+ watcher.EventArrived += (sender, args) =>
+ {
+ var newWindowsTheme = GetWindowsTheme();
+ OnThemeChanged(new WindowsThemeEventArgs(newWindowsTheme));
+ };
+
+ // Start listening for events
+ watcher.Start();
+ }
+ catch (Exception)
+ {
+ // This can fail on Windows 7
+ }
+ }
+
+ public WindowsTheme GetWindowsTheme()
+ {
+ using (var key = Registry.CurrentUser.OpenSubKey(RegistryKeyPath))
+ {
+ var registryValueObject = key?.GetValue(RegistryValueName);
+ if (registryValueObject == null) return WindowsTheme.Light;
+
+ var registryValue = (int) registryValueObject;
+
+ return registryValue > 0 ? WindowsTheme.Light : WindowsTheme.Dark;
+ }
+ }
+
+ public event EventHandler ThemeChanged;
+
+
+ protected virtual void OnThemeChanged(WindowsThemeEventArgs e)
+ {
+ ThemeChanged?.Invoke(this, e);
+ }
+ }
+}
\ No newline at end of file