Browse Source

Implement :light-selector pseudo class

pull/7842/head
robloo 5 years ago
parent
commit
a0acdb2297
  1. 26
      src/Avalonia.Controls/ColorPicker/ColorSpectrum/ColorHelpers.cs
  2. 29
      src/Avalonia.Controls/ColorPicker/ColorSpectrum/ColorSpectrum.cs
  3. 35
      src/Avalonia.Themes.Fluent/Controls/ColorSpectrum.xaml

26
src/Avalonia.Controls/ColorPicker/ColorSpectrum/ColorHelpers.cs

@ -384,5 +384,31 @@ namespace Avalonia.Controls.Primitives
return bitmap; return bitmap;
} }
/// <summary>
/// Gets the relative (perceptual) luminance/brightness of the given color.
/// 1 is closer to white while 0 is closer to black.
/// </summary>
/// <param name="color">The color to calculate relative luminance for.</param>
/// <returns>The relative (perceptual) luminance/brightness of the given color.</returns>
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);
}
} }
} }

29
src/Avalonia.Controls/ColorPicker/ColorSpectrum/ColorSpectrum.cs

@ -6,6 +6,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks; using System.Threading.Tasks;
using Avalonia.Controls.Metadata;
using Avalonia.Controls.Shapes; using Avalonia.Controls.Shapes;
using Avalonia.Input; using Avalonia.Input;
using Avalonia.Interactivity; using Avalonia.Interactivity;
@ -19,8 +20,11 @@ namespace Avalonia.Controls.Primitives
/// <summary> /// <summary>
/// A two dimensional spectrum for color selection. /// A two dimensional spectrum for color selection.
/// </summary> /// </summary>
[PseudoClasses(pcLightSelector)]
public partial class ColorSpectrum : TemplatedControl public partial class ColorSpectrum : TemplatedControl
{ {
protected const string pcLightSelector = ":light-selector";
/// <summary> /// <summary>
/// Event for when the selected color changes within the spectrum. /// Event for when the selected color changes within the spectrum.
/// </summary> /// </summary>
@ -526,7 +530,7 @@ namespace Avalonia.Controls.Primitives
// VisualStateManager.GoToState(this, "Normal", useTransitions); // VisualStateManager.GoToState(this, "Normal", useTransitions);
//} //}
//VisualStateManager.GoToState(this, SelectionEllipseShouldBeLight() ? "SelectionEllipseLight" : "SelectionEllipseDark", useTransitions); PseudoClasses.Set(pcLightSelector, SelectionEllipseShouldBeLight());
//if (IsEnabled && FocusState != FocusState.Unfocused) //if (IsEnabled && FocusState != FocusState.Unfocused)
//{ //{
@ -1574,23 +1578,18 @@ namespace Avalonia.Controls.Primitives
} }
} }
/// <summary>
/// Determines whether the selection ellipse should be light based on the relative
/// luminance of the selected color.
/// </summary>
private bool SelectionEllipseShouldBeLight() private bool SelectionEllipseShouldBeLight()
{ {
// The selection ellipse should be light if and only if the chosen color // The selection ellipse should be light if and only if the chosen color
// contrasts more with black than it does with white. // contrasts more with black than it does with white.
// To find how much something contrasts with white, we use the equation // To find how much something contrasts with white, we use the equation
// for relative luminance, which is given by // for relative luminance.
//
// 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.
// //
// 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 // so in that case we should use a value of 1 when considering the backdrop
// for the selection ellipse. // for the selection ellipse.
Color displayedColor; Color displayedColor;
@ -1607,11 +1606,9 @@ namespace Avalonia.Controls.Primitives
displayedColor = Color; displayedColor = Color;
} }
double rg = displayedColor.R <= 10 ? displayedColor.R / 3294.0 : Math.Pow(displayedColor.R / 269.0 + 0.0513, 2.4); var lum = ColorHelpers.GetRelativeLuminance(displayedColor);
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);
return ((0.2126 * rg + 0.7152 * gg + 0.0722 * bg) <= 0.5); return lum <= 0.5;
} }
} }
} }

35
src/Avalonia.Themes.Fluent/Controls/ColorSpectrum.xaml

@ -4,6 +4,9 @@
xmlns:converters="using:Avalonia.Controls.Converters"> xmlns:converters="using:Avalonia.Controls.Converters">
<Design.PreviewWith> <Design.PreviewWith>
<Border Padding="20">
<ColorSpectrum Width="256" Height="256" />
</Border>
</Design.PreviewWith> </Design.PreviewWith>
<Styles.Resources> <Styles.Resources>
@ -53,7 +56,6 @@
Width="16" Width="16"
Height="16"> Height="16">
<Ellipse x:Name="FocusEllipse" <Ellipse x:Name="FocusEllipse"
Stroke="{DynamicResource SystemControlBackgroundChromeBlackHighBrush}"
Margin="-2" Margin="-2"
StrokeThickness="2" StrokeThickness="2"
IsHitTestVisible="False" IsHitTestVisible="False"
@ -61,7 +63,6 @@
VerticalAlignment="Stretch" VerticalAlignment="Stretch"
IsVisible="False" /> IsVisible="False" />
<Ellipse x:Name="SelectionEllipse" <Ellipse x:Name="SelectionEllipse"
Stroke="{DynamicResource SystemControlBackgroundChromeWhiteBrush}"
StrokeThickness="2" StrokeThickness="2"
IsHitTestVisible="False" IsHitTestVisible="False"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
@ -97,6 +98,20 @@
</Setter> </Setter>
</Style> </Style>
<!-- SelectionEllipseColor -->
<Style Selector="ColorSpectrum /template/ Ellipse#FocusEllipse">
<Setter Property="Stroke" Value="{DynamicResource SystemControlBackgroundChromeWhiteBrush}" />
</Style>
<Style Selector="ColorSpectrum /template/ Ellipse#SelectionEllipse">
<Setter Property="Stroke" Value="{DynamicResource SystemControlBackgroundChromeBlackHighBrush}" />
</Style>
<Style Selector="ColorSpectrum:light-selector /template/ Ellipse#FocusEllipse">
<Setter Property="Stroke" Value="{DynamicResource SystemControlBackgroundChromeBlackHighBrush}" />
</Style>
<Style Selector="ColorSpectrum:light-selector /template/ Ellipse#SelectionEllipse">
<Setter Property="Stroke" Value="{DynamicResource SystemControlBackgroundChromeWhiteBrush}" />
</Style>
<!--<VisualStateManager.VisualStateGroups> <!--<VisualStateManager.VisualStateGroups>
<VisualStateGroup <VisualStateGroup
x:Name="CommonStates"> x:Name="CommonStates">
@ -124,22 +139,6 @@
</VisualState.Setters> </VisualState.Setters>
</VisualState> </VisualState>
</VisualStateGroup> </VisualStateGroup>
<VisualStateGroup
x:Name="SelectionEllipseColor">
<VisualState
x:Name="SelectionEllipseLight" />
<VisualState
x:Name="SelectionEllipseDark">
<VisualState.Setters>
<Setter
Target="FocusEllipse.Stroke"
Value="{ThemeResource SystemControlBackgroundChromeWhiteBrush}" />
<Setter
Target="SelectionEllipse.Stroke"
Value="{ThemeResource SystemControlBackgroundChromeBlackHighBrush}" />
</VisualState.Setters>
</VisualState>
</VisualStateGroup>
<VisualStateGroup <VisualStateGroup
x:Name="FocusStates"> x:Name="FocusStates">
<VisualState <VisualState

Loading…
Cancel
Save