diff --git a/src/Avalonia.Controls/ColorPicker/ColorSpectrum/ColorHelpers.cs b/src/Avalonia.Controls/ColorPicker/ColorSpectrum/ColorHelpers.cs index 3d380392aa..0cdda28b9c 100644 --- a/src/Avalonia.Controls/ColorPicker/ColorSpectrum/ColorHelpers.cs +++ b/src/Avalonia.Controls/ColorPicker/ColorSpectrum/ColorHelpers.cs @@ -384,5 +384,31 @@ namespace Avalonia.Controls.Primitives return bitmap; } + + /// + /// Gets the relative (perceptual) luminance/brightness of the given color. + /// 1 is closer to white while 0 is closer to black. + /// + /// The color to calculate relative luminance for. + /// The relative (perceptual) luminance/brightness of the given color. + public static double GetRelativeLuminance(Color color) + { + // The equation for relative luminance is given by + // + // L = 0.2126 * Rg + 0.7152 * Gg + 0.0722 * Bg + // + // where Xg = { X/3294 if X <= 10, (R/269 + 0.0513)^2.4 otherwise } + // + // If L is closer to 1, then the color is closer to white; if it is closer to 0, + // then the color is closer to black. This is based on the fact that the human + // eye perceives green to be much brighter than red, which in turn is perceived to be + // brighter than blue. + + double rg = color.R <= 10 ? color.R / 3294.0 : Math.Pow(color.R / 269.0 + 0.0513, 2.4); + double gg = color.G <= 10 ? color.G / 3294.0 : Math.Pow(color.G / 269.0 + 0.0513, 2.4); + double bg = color.B <= 10 ? color.B / 3294.0 : Math.Pow(color.B / 269.0 + 0.0513, 2.4); + + return (0.2126 * rg + 0.7152 * gg + 0.0722 * bg); + } } } diff --git a/src/Avalonia.Controls/ColorPicker/ColorSpectrum/ColorSpectrum.cs b/src/Avalonia.Controls/ColorPicker/ColorSpectrum/ColorSpectrum.cs index ef07e56f10..e95f911235 100644 --- a/src/Avalonia.Controls/ColorPicker/ColorSpectrum/ColorSpectrum.cs +++ b/src/Avalonia.Controls/ColorPicker/ColorSpectrum/ColorSpectrum.cs @@ -6,6 +6,7 @@ using System; using System.Collections.Generic; using System.Threading.Tasks; +using Avalonia.Controls.Metadata; using Avalonia.Controls.Shapes; using Avalonia.Input; using Avalonia.Interactivity; @@ -19,8 +20,11 @@ namespace Avalonia.Controls.Primitives /// /// A two dimensional spectrum for color selection. /// + [PseudoClasses(pcLightSelector)] public partial class ColorSpectrum : TemplatedControl { + protected const string pcLightSelector = ":light-selector"; + /// /// Event for when the selected color changes within the spectrum. /// @@ -526,7 +530,7 @@ namespace Avalonia.Controls.Primitives // VisualStateManager.GoToState(this, "Normal", useTransitions); //} - //VisualStateManager.GoToState(this, SelectionEllipseShouldBeLight() ? "SelectionEllipseLight" : "SelectionEllipseDark", useTransitions); + PseudoClasses.Set(pcLightSelector, SelectionEllipseShouldBeLight()); //if (IsEnabled && FocusState != FocusState.Unfocused) //{ @@ -1574,23 +1578,18 @@ namespace Avalonia.Controls.Primitives } } + /// + /// Determines whether the selection ellipse should be light based on the relative + /// luminance of the selected color. + /// private bool SelectionEllipseShouldBeLight() { // The selection ellipse should be light if and only if the chosen color // contrasts more with black than it does with white. // To find how much something contrasts with white, we use the equation - // for relative luminance, which is given by - // - // L = 0.2126 * Rg + 0.7152 * Gg + 0.0722 * Bg - // - // where Xg = { X/3294 if X <= 10, (R/269 + 0.0513)^2.4 otherwise } - // - // If L is closer to 1, then the color is closer to white; if it is closer to 0, - // then the color is closer to black. This is based on the fact that the human - // eye perceives green to be much brighter than red, which in turn is perceived to be - // brighter than blue. + // for relative luminance. // - // If the third dimension is value, then we won't be updating the spectrum's displayed colors, + // If the third channel is value, then we won't be updating the spectrum's displayed colors, // so in that case we should use a value of 1 when considering the backdrop // for the selection ellipse. Color displayedColor; @@ -1607,11 +1606,9 @@ namespace Avalonia.Controls.Primitives displayedColor = Color; } - double rg = displayedColor.R <= 10 ? displayedColor.R / 3294.0 : Math.Pow(displayedColor.R / 269.0 + 0.0513, 2.4); - double gg = displayedColor.G <= 10 ? displayedColor.G / 3294.0 : Math.Pow(displayedColor.G / 269.0 + 0.0513, 2.4); - double bg = displayedColor.B <= 10 ? displayedColor.B / 3294.0 : Math.Pow(displayedColor.B / 269.0 + 0.0513, 2.4); + var lum = ColorHelpers.GetRelativeLuminance(displayedColor); - return ((0.2126 * rg + 0.7152 * gg + 0.0722 * bg) <= 0.5); + return lum <= 0.5; } } } diff --git a/src/Avalonia.Themes.Fluent/Controls/ColorSpectrum.xaml b/src/Avalonia.Themes.Fluent/Controls/ColorSpectrum.xaml index 0d6ed59c68..84eec272ed 100644 --- a/src/Avalonia.Themes.Fluent/Controls/ColorSpectrum.xaml +++ b/src/Avalonia.Themes.Fluent/Controls/ColorSpectrum.xaml @@ -4,6 +4,9 @@ xmlns:converters="using:Avalonia.Controls.Converters"> + + + @@ -53,7 +56,6 @@ Width="16" Height="16"> + + + + + +