diff --git a/MainDemo.Wpf/Domain/PaletteSelectorViewModel.cs b/MainDemo.Wpf/Domain/PaletteSelectorViewModel.cs index b81867a2e5..fa87ed669f 100644 --- a/MainDemo.Wpf/Domain/PaletteSelectorViewModel.cs +++ b/MainDemo.Wpf/Domain/PaletteSelectorViewModel.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.Linq; using System.Windows.Input; using MaterialDesignColors; using MaterialDesignThemes.Wpf; @@ -17,6 +18,16 @@ public PaletteSelectorViewModel() IsDarkTheme = theme.GetBaseTheme() == BaseTheme.Dark; + if (theme is Theme internalTheme) + { + _isColorAdjusted = internalTheme.ColorAdjustment is not null; + + var colorAdjustment = internalTheme.ColorAdjustment ?? new ColorAdjustment(); + _desiredContrastRatio = colorAdjustment.DesiredContrastRatio; + _contrastValue = colorAdjustment.Contrast; + _colorSelectionValue = colorAdjustment.Colors; + } + if (paletteHelper.GetThemeManager() is { } themeManager) { themeManager.ThemeChanged += (_, e) => @@ -39,6 +50,87 @@ public bool IsDarkTheme } } + private bool _isColorAdjusted; + public bool IsColorAdjusted + { + get => _isColorAdjusted; + set + { + if (SetProperty(ref _isColorAdjusted, value)) + { + ModifyTheme(theme => + { + if (theme is Theme internalTheme) + { + internalTheme.ColorAdjustment = value + ? new ColorAdjustment + { + DesiredContrastRatio = DesiredContrastRatio, + Contrast = ContrastValue, + Colors = ColorSelectionValue + } + : null; + } + }); + } + } + } + + private float _desiredContrastRatio = 4.5f; + public float DesiredContrastRatio + { + get => _desiredContrastRatio; + set + { + if (SetProperty(ref _desiredContrastRatio, value)) + { + ModifyTheme(theme => + { + if (theme is Theme internalTheme && internalTheme.ColorAdjustment != null) + internalTheme.ColorAdjustment.DesiredContrastRatio = value; + }); + } + } + } + + public IEnumerable ContrastValues => Enum.GetValues(typeof(Contrast)).Cast(); + + private Contrast _contrastValue; + public Contrast ContrastValue + { + get => _contrastValue; + set + { + if (SetProperty(ref _contrastValue, value)) + { + ModifyTheme(theme => + { + if (theme is Theme internalTheme && internalTheme.ColorAdjustment != null) + internalTheme.ColorAdjustment.Contrast = value; + }); + } + } + } + + public IEnumerable ColorSelectionValues => Enum.GetValues(typeof(ColorSelection)).Cast(); + + private ColorSelection _colorSelectionValue; + public ColorSelection ColorSelectionValue + { + get => _colorSelectionValue; + set + { + if (SetProperty(ref _colorSelectionValue, value)) + { + ModifyTheme(theme => + { + if (theme is Theme internalTheme && internalTheme.ColorAdjustment != null) + internalTheme.ColorAdjustment.Colors = value; + }); + } + } + } + public IEnumerable Swatches { get; } public ICommand ApplyPrimaryCommand { get; } = new AnotherCommandImplementation(o => ApplyPrimary((Swatch)o)); diff --git a/MainDemo.Wpf/PaletteSelector.xaml b/MainDemo.Wpf/PaletteSelector.xaml index 6044633be8..57528447c2 100644 --- a/MainDemo.Wpf/PaletteSelector.xaml +++ b/MainDemo.Wpf/PaletteSelector.xaml @@ -10,7 +10,7 @@ xmlns:wpf="clr-namespace:MaterialDesignThemes.Wpf;assembly=MaterialDesignThemes.Wpf" d:DataContext="{d:DesignInstance domain:PaletteSelectorViewModel}" d:DesignHeight="300" - d:DesignWidth="300" + d:DesignWidth="400" mc:Ignorable="d"> @@ -143,6 +143,81 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + = 3.0); + Assert.True(contrastRatio >= 2.9); Assert.True(contrastRatio <= 3.1); } } diff --git a/MaterialDesignColors.Wpf/ColorManipulation/ColorAssist.cs b/MaterialDesignColors.Wpf/ColorManipulation/ColorAssist.cs index d837aca2ac..29799c7110 100644 --- a/MaterialDesignColors.Wpf/ColorManipulation/ColorAssist.cs +++ b/MaterialDesignColors.Wpf/ColorManipulation/ColorAssist.cs @@ -88,7 +88,7 @@ public static Color EnsureContrastRatio(this Color foreground, Color background, Color finalColor = foreground; double? adjust = null; - while ((ratio < targetRatio || ratio > targetRatio + tollerance) && + while ((ratio < targetRatio - tollerance || ratio > targetRatio + tollerance) && finalColor != Colors.White && finalColor != Colors.Black) { diff --git a/MaterialDesignThemes.UITests/WPF/Theme/ColorAdjustTests.cs b/MaterialDesignThemes.UITests/WPF/Theme/ColorAdjustTests.cs index 1fc54e1ea1..b137e1f732 100644 --- a/MaterialDesignThemes.UITests/WPF/Theme/ColorAdjustTests.cs +++ b/MaterialDesignThemes.UITests/WPF/Theme/ColorAdjustTests.cs @@ -55,6 +55,7 @@ public async Task PrimaryColor_AdjustToTheme(PrimaryColor primary) async Task AssertContrastRatio() { + const double tollerance = 0.1; Color? largeTextForeground = await largeText.GetForegroundColor(); Color largeTextBackground = await largeText.GetEffectiveBackground(); @@ -62,9 +63,9 @@ async Task AssertContrastRatio() Color smallTextBackground = await smallText.GetEffectiveBackground(); var largeContrastRatio = ColorAssist.ContrastRatio(largeTextForeground.Value, largeTextBackground); - Assert.True(largeContrastRatio >= MaterialDesignSpec.MinimumContrastLargeText, $"Large font contrast ratio '{largeContrastRatio}' does not meet material design spec {MaterialDesignSpec.MinimumContrastLargeText}"); + Assert.True(largeContrastRatio >= MaterialDesignSpec.MinimumContrastLargeText - tollerance, $"Large font contrast ratio '{largeContrastRatio}' does not meet material design spec {MaterialDesignSpec.MinimumContrastLargeText}"); var smallContrastRatio = ColorAssist.ContrastRatio(smallTextForeground.Value, smallTextBackground); - Assert.True(smallContrastRatio >= MaterialDesignSpec.MinimumContrastSmallText, $"Small font contrast ratio '{smallContrastRatio}' does not meet material design spec {MaterialDesignSpec.MinimumContrastSmallText}"); + Assert.True(smallContrastRatio >= MaterialDesignSpec.MinimumContrastSmallText - tollerance, $"Small font contrast ratio '{smallContrastRatio}' does not meet material design spec {MaterialDesignSpec.MinimumContrastSmallText}"); } } }