mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Added dark mode 🦇
This commit is contained in:
parent
8430f28fa7
commit
8f3d2f1ff5
@ -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)
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -139,6 +139,7 @@
|
||||
<Reference Include="System.ComponentModel.DataAnnotations" />
|
||||
<Reference Include="System.Configuration" />
|
||||
<Reference Include="System.Drawing" />
|
||||
<Reference Include="System.Management" />
|
||||
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
|
||||
<HintPath>..\packages\System.Memory.4.5.3\lib\netstandard2.0\System.Memory.dll</HintPath>
|
||||
</Reference>
|
||||
@ -170,6 +171,9 @@
|
||||
<SubType>Designer</SubType>
|
||||
</ApplicationDefinition>
|
||||
<Compile Include="Bootstrapper.cs" />
|
||||
<Compile Include="Controls\ColorPicker\ColorPickerView.xaml.cs">
|
||||
<DependentUpon>ColorPickerView.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Converters\ColorToDrawingColorConverter.cs" />
|
||||
<Compile Include="Converters\ColorToSolidColorBrushConverter.cs" />
|
||||
<Compile Include="Converters\EnumToCollectionConverter.cs" />
|
||||
@ -177,11 +181,13 @@
|
||||
<Compile Include="Converters\NullToImageConverter.cs" />
|
||||
<Compile Include="Converters\NullToVisibilityConverter.cs" />
|
||||
<Compile Include="Events\MainWindowFocusChangedEvent.cs" />
|
||||
<Compile Include="Events\WindowsThemeEventArgs.cs" />
|
||||
<Compile Include="Screens\GradientEditor\GradientEditorViewModel.cs" />
|
||||
<Compile Include="Screens\Module\ProfileEditor\LayerElements\Dialogs\AddLayerElementViewModel.cs" />
|
||||
<Compile Include="Services\Interfaces\IProfileEditorService.cs" />
|
||||
<Compile Include="Services\ProfileEditorService.cs" />
|
||||
<Compile Include="Utilities\BindableSelectedItemBehavior.cs" />
|
||||
<Compile Include="Utilities\ThemeWatcher.cs" />
|
||||
<Compile Include="Utilities\TriggerTracing.cs" />
|
||||
<Compile Include="Exceptions\ArtemisCoreException.cs" />
|
||||
<Compile Include="Extensions\RgbColorExtensions.cs" />
|
||||
@ -247,6 +253,10 @@
|
||||
<SubType>Code</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Screens\Settings\SettingsViewModel.cs" />
|
||||
<Page Include="Controls\ColorPicker\ColorPickerView.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="ResourceDictionaries\Scrollbar.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
||||
13
src/Artemis.UI/Controls/ColorPicker/ColorPickerView.xaml
Normal file
13
src/Artemis.UI/Controls/ColorPicker/ColorPickerView.xaml
Normal file
@ -0,0 +1,13 @@
|
||||
<UserControl x:Class="Artemis.UI.Controls.ColorPicker.ColorPickerView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:Artemis.UI.Controls.ColorPicker"
|
||||
xmlns:wpf="http://materialdesigninxaml.net/winfx/xaml/themes"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
|
||||
</Grid>
|
||||
</UserControl>
|
||||
28
src/Artemis.UI/Controls/ColorPicker/ColorPickerView.xaml.cs
Normal file
28
src/Artemis.UI/Controls/ColorPicker/ColorPickerView.xaml.cs
Normal file
@ -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
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for ColorPickerView.xaml
|
||||
/// </summary>
|
||||
public partial class ColorPickerView : UserControl
|
||||
{
|
||||
public ColorPickerView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
}
|
||||
15
src/Artemis.UI/Events/WindowsThemeEventArgs.cs
Normal file
15
src/Artemis.UI/Events/WindowsThemeEventArgs.cs
Normal file
@ -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; }
|
||||
}
|
||||
}
|
||||
@ -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 @@
|
||||
</Grid.LayoutTransform>
|
||||
|
||||
<!-- Device image with fallback -->
|
||||
<Image Source="{Binding Device.RgbDevice.DeviceInfo.Image, Converter={StaticResource NullToImageConverter}}" VerticalAlignment="Top" HorizontalAlignment="Left" />
|
||||
<Border Effect="{StaticResource MaterialDesignShadowDepth3}" VerticalAlignment="Top" HorizontalAlignment="Left" >
|
||||
<Image Source="{Binding Device.RgbDevice.DeviceInfo.Image, Converter={StaticResource NullToImageConverter}}"/>
|
||||
</Border>
|
||||
|
||||
<Rectangle Fill="{DynamicResource ControlBackgroundBrush}"
|
||||
Stroke="{DynamicResource ControlBorderBrush}"
|
||||
|
||||
@ -51,7 +51,7 @@
|
||||
<Grid.Background>
|
||||
<VisualBrush TileMode="Tile" Stretch="Uniform" Viewport="{Binding PanZoomViewModel.BackgroundViewport}" ViewportUnits="Absolute">
|
||||
<VisualBrush.Visual>
|
||||
<Grid Width="20" Height="20">
|
||||
<Grid Width="25" Height="25">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
@ -60,10 +60,10 @@
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
<Rectangle Grid.Row="0" Grid.Column="0" Fill="LightGray" />
|
||||
<Rectangle Grid.Row="0" Grid.Column="0" Fill="{DynamicResource MaterialDesignPaper}" />
|
||||
<Rectangle Grid.Row="0" Grid.Column="1" />
|
||||
<Rectangle Grid.Row="1" Grid.Column="0" />
|
||||
<Rectangle Grid.Row="1" Grid.Column="1" Fill="LightGray" />
|
||||
<Rectangle Grid.Row="1" Grid.Column="0" />
|
||||
<Rectangle Grid.Row="1" Grid.Column="1" Fill="{DynamicResource MaterialDesignPaper}" />
|
||||
</Grid>
|
||||
</VisualBrush.Visual>
|
||||
</VisualBrush>
|
||||
|
||||
@ -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}"
|
||||
|
||||
@ -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<Core.Plugins.Abstract.Module> Modules { get; set; }
|
||||
|
||||
@ -8,6 +8,6 @@
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<Grid>
|
||||
<TextBlock>Work work!</TextBlock>
|
||||
<TextBlock Style="{DynamicResource MaterialDesignBody1TextBlock}">Work work!</TextBlock>
|
||||
</Grid>
|
||||
</UserControl>
|
||||
76
src/Artemis.UI/Utilities/ThemeWatcher.cs
Normal file
76
src/Artemis.UI/Utilities/ThemeWatcher.cs
Normal file
@ -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<WindowsThemeEventArgs> ThemeChanged;
|
||||
|
||||
|
||||
protected virtual void OnThemeChanged(WindowsThemeEventArgs e)
|
||||
{
|
||||
ThemeChanged?.Invoke(this, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user