12 changed files with 1042 additions and 31 deletions
@ -0,0 +1,413 @@ |
|||||
|
using System; |
||||
|
using System.Windows; |
||||
|
using System.Windows.Controls; |
||||
|
using System.Windows.Input; |
||||
|
using System.Windows.Media; |
||||
|
using Microsoft.Windows.Controls.Primitives; |
||||
|
using Microsoft.Windows.Controls.Core.Utilities; |
||||
|
|
||||
|
namespace Microsoft.Windows.Controls |
||||
|
{ |
||||
|
public class ColorCanvas : Control |
||||
|
{ |
||||
|
#region Private Members
|
||||
|
|
||||
|
private TranslateTransform _colorShadeSelectorTransform = new TranslateTransform(); |
||||
|
private Canvas _colorShadingCanvas; |
||||
|
private Canvas _colorShadeSelector; |
||||
|
private ColorSpectrumSlider _spectrumSlider; |
||||
|
private Point? _currentColorPosition; |
||||
|
|
||||
|
#endregion //Private Members
|
||||
|
|
||||
|
#region Properties
|
||||
|
|
||||
|
#region SelectedColor
|
||||
|
|
||||
|
public static readonly DependencyProperty SelectedColorProperty = DependencyProperty.Register("SelectedColor", typeof(Color), typeof(ColorCanvas), new UIPropertyMetadata(Colors.White, OnSelectedColorChanged)); |
||||
|
public Color SelectedColor |
||||
|
{ |
||||
|
get { return (Color)GetValue(SelectedColorProperty); } |
||||
|
set { SetValue(SelectedColorProperty, value); } |
||||
|
} |
||||
|
|
||||
|
private static void OnSelectedColorChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
ColorCanvas colorCanvas = o as ColorCanvas; |
||||
|
if (colorCanvas != null) |
||||
|
colorCanvas.OnSelectedColorChanged((Color)e.OldValue, (Color)e.NewValue); |
||||
|
} |
||||
|
|
||||
|
protected virtual void OnSelectedColorChanged(Color oldValue, Color newValue) |
||||
|
{ |
||||
|
UpdateRGBValues(newValue); |
||||
|
} |
||||
|
|
||||
|
#endregion //SelectedColor
|
||||
|
|
||||
|
#region RGB
|
||||
|
|
||||
|
#region A
|
||||
|
|
||||
|
public static readonly DependencyProperty AProperty = DependencyProperty.Register("A", typeof(byte), typeof(ColorCanvas), new UIPropertyMetadata((byte)255, new PropertyChangedCallback(OnAChanged), new CoerceValueCallback(OnCoerceA))); |
||||
|
|
||||
|
private static object OnCoerceA(DependencyObject o, object value) |
||||
|
{ |
||||
|
ColorCanvas colorCanvas = o as ColorCanvas; |
||||
|
if (colorCanvas != null) |
||||
|
return colorCanvas.OnCoerceA((byte)value); |
||||
|
else |
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
private static void OnAChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
ColorCanvas colorCanvas = o as ColorCanvas; |
||||
|
if (colorCanvas != null) |
||||
|
colorCanvas.OnAChanged((byte)e.OldValue, (byte)e.NewValue); |
||||
|
} |
||||
|
|
||||
|
protected virtual byte OnCoerceA(byte value) |
||||
|
{ |
||||
|
// TODO: Keep the proposed value within the desired range.
|
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
protected virtual void OnAChanged(byte oldValue, byte newValue) |
||||
|
{ |
||||
|
UpdateRGBColor(); |
||||
|
} |
||||
|
|
||||
|
public byte A |
||||
|
{ |
||||
|
// IMPORTANT: To maintain parity between setting a property in XAML and procedural code, do not touch the getter and setter inside this dependency property!
|
||||
|
get |
||||
|
{ |
||||
|
return (byte)GetValue(AProperty); |
||||
|
} |
||||
|
set |
||||
|
{ |
||||
|
SetValue(AProperty, value); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion //A
|
||||
|
|
||||
|
#region R
|
||||
|
|
||||
|
public static readonly DependencyProperty RProperty = DependencyProperty.Register("R", typeof(byte), typeof(ColorCanvas), new UIPropertyMetadata((byte)255, new PropertyChangedCallback(OnRChanged), new CoerceValueCallback(OnCoerceR))); |
||||
|
|
||||
|
private static object OnCoerceR(DependencyObject o, object value) |
||||
|
{ |
||||
|
ColorCanvas colorCanvas = o as ColorCanvas; |
||||
|
if (colorCanvas != null) |
||||
|
return colorCanvas.OnCoerceR((byte)value); |
||||
|
else |
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
private static void OnRChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
ColorCanvas colorCanvas = o as ColorCanvas; |
||||
|
if (colorCanvas != null) |
||||
|
colorCanvas.OnRChanged((byte)e.OldValue, (byte)e.NewValue); |
||||
|
} |
||||
|
|
||||
|
protected virtual byte OnCoerceR(byte value) |
||||
|
{ |
||||
|
// TODO: Keep the proposed value within the desired range.
|
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
protected virtual void OnRChanged(byte oldValue, byte newValue) |
||||
|
{ |
||||
|
UpdateRGBColor(); |
||||
|
} |
||||
|
|
||||
|
public byte R |
||||
|
{ |
||||
|
// IMPORTANT: To maintain parity between setting a property in XAML and procedural code, do not touch the getter and setter inside this dependency property!
|
||||
|
get |
||||
|
{ |
||||
|
return (byte)GetValue(RProperty); |
||||
|
} |
||||
|
set |
||||
|
{ |
||||
|
SetValue(RProperty, value); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
#endregion //R
|
||||
|
|
||||
|
#region G
|
||||
|
|
||||
|
public static readonly DependencyProperty GProperty = DependencyProperty.Register("G", typeof(byte), typeof(ColorCanvas), new UIPropertyMetadata((byte)255, new PropertyChangedCallback(OnGChanged), new CoerceValueCallback(OnCoerceG))); |
||||
|
|
||||
|
private static object OnCoerceG(DependencyObject o, object value) |
||||
|
{ |
||||
|
ColorCanvas colorCanvas = o as ColorCanvas; |
||||
|
if (colorCanvas != null) |
||||
|
return colorCanvas.OnCoerceG((byte)value); |
||||
|
else |
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
private static void OnGChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
ColorCanvas colorCanvas = o as ColorCanvas; |
||||
|
if (colorCanvas != null) |
||||
|
colorCanvas.OnGChanged((byte)e.OldValue, (byte)e.NewValue); |
||||
|
} |
||||
|
|
||||
|
protected virtual byte OnCoerceG(byte value) |
||||
|
{ |
||||
|
// TODO: Keep the proposed value within the desired range.
|
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
protected virtual void OnGChanged(byte oldValue, byte newValue) |
||||
|
{ |
||||
|
UpdateRGBColor(); |
||||
|
} |
||||
|
|
||||
|
public byte G |
||||
|
{ |
||||
|
// IMPORTANT: To maintain parity between setting a property in XAML and procedural code, do not touch the getter and setter inside this dependency property!
|
||||
|
get |
||||
|
{ |
||||
|
return (byte)GetValue(GProperty); |
||||
|
} |
||||
|
set |
||||
|
{ |
||||
|
SetValue(GProperty, value); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
#endregion //G
|
||||
|
|
||||
|
#region B
|
||||
|
|
||||
|
public static readonly DependencyProperty BProperty = DependencyProperty.Register("B", typeof(byte), typeof(ColorCanvas), new UIPropertyMetadata((byte)255, new PropertyChangedCallback(OnBChanged), new CoerceValueCallback(OnCoerceB))); |
||||
|
|
||||
|
private static object OnCoerceB(DependencyObject o, object value) |
||||
|
{ |
||||
|
ColorCanvas colorCanvas = o as ColorCanvas; |
||||
|
if (colorCanvas != null) |
||||
|
return colorCanvas.OnCoerceB((byte)value); |
||||
|
else |
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
private static void OnBChanged(DependencyObject o, DependencyPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
ColorCanvas colorCanvas = o as ColorCanvas; |
||||
|
if (colorCanvas != null) |
||||
|
colorCanvas.OnBChanged((byte)e.OldValue, (byte)e.NewValue); |
||||
|
} |
||||
|
|
||||
|
protected virtual byte OnCoerceB(byte value) |
||||
|
{ |
||||
|
// TODO: Keep the proposed value within the desired range.
|
||||
|
return value; |
||||
|
} |
||||
|
|
||||
|
protected virtual void OnBChanged(byte oldValue, byte newValue) |
||||
|
{ |
||||
|
UpdateRGBColor(); |
||||
|
} |
||||
|
|
||||
|
public byte B |
||||
|
{ |
||||
|
// IMPORTANT: To maintain parity between setting a property in XAML and procedural code, do not touch the getter and setter inside this dependency property!
|
||||
|
get |
||||
|
{ |
||||
|
return (byte)GetValue(BProperty); |
||||
|
} |
||||
|
set |
||||
|
{ |
||||
|
SetValue(BProperty, value); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
#endregion //B
|
||||
|
|
||||
|
#endregion //RGB
|
||||
|
|
||||
|
#region HexadecimalString
|
||||
|
|
||||
|
public static readonly DependencyProperty HexadecimalStringProperty = DependencyProperty.Register("HexadecimalString", typeof(string), typeof(ColorCanvas), new PropertyMetadata("#FFFFFFFF", new PropertyChangedCallback(OnHexadecimalStringPropertyChanged))); |
||||
|
public string HexadecimalString |
||||
|
{ |
||||
|
get { return (string)GetValue(HexadecimalStringProperty); } |
||||
|
set { SetValue(HexadecimalStringProperty, value); } |
||||
|
} |
||||
|
|
||||
|
private static void OnHexadecimalStringPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) |
||||
|
{ |
||||
|
|
||||
|
} |
||||
|
|
||||
|
#endregion //HexadecimalString
|
||||
|
|
||||
|
#endregion //Properties
|
||||
|
|
||||
|
#region Constructors
|
||||
|
|
||||
|
static ColorCanvas() |
||||
|
{ |
||||
|
DefaultStyleKeyProperty.OverrideMetadata(typeof(ColorCanvas), new FrameworkPropertyMetadata(typeof(ColorCanvas))); |
||||
|
} |
||||
|
|
||||
|
#endregion //Constructors
|
||||
|
|
||||
|
#region Base Class Overrides
|
||||
|
|
||||
|
public override void OnApplyTemplate() |
||||
|
{ |
||||
|
base.OnApplyTemplate(); |
||||
|
|
||||
|
_colorShadingCanvas = (Canvas)GetTemplateChild("PART_ColorShadingCanvas"); |
||||
|
_colorShadingCanvas.MouseLeftButtonDown += ColorShadingCanvas_MouseLeftButtonDown; |
||||
|
_colorShadingCanvas.MouseMove += ColorShadingCanvas_MouseMove; |
||||
|
_colorShadingCanvas.SizeChanged += ColorShadingCanvas_SizeChanged; |
||||
|
|
||||
|
_colorShadeSelector = (Canvas)GetTemplateChild("PART_ColorShadeSelector"); |
||||
|
_colorShadeSelector.RenderTransform = _colorShadeSelectorTransform; |
||||
|
|
||||
|
_spectrumSlider = (ColorSpectrumSlider)GetTemplateChild("PART_SpectrumSlider"); |
||||
|
_spectrumSlider.ValueChanged += SpectrumSlider_ValueChanged; |
||||
|
|
||||
|
SetSelectedColorAndPositionSelector(SelectedColor); |
||||
|
} |
||||
|
|
||||
|
#endregion //Base Class Overrides
|
||||
|
|
||||
|
#region Event Handlers
|
||||
|
|
||||
|
void ColorShadingCanvas_MouseLeftButtonDown(object sender, MouseButtonEventArgs e) |
||||
|
{ |
||||
|
Point p = e.GetPosition(_colorShadingCanvas); |
||||
|
UpdateColorShadeSelectorPositionAndCalculateColor(p, true); |
||||
|
} |
||||
|
|
||||
|
void ColorShadingCanvas_MouseMove(object sender, MouseEventArgs e) |
||||
|
{ |
||||
|
if (e.LeftButton == MouseButtonState.Pressed) |
||||
|
{ |
||||
|
Point p = e.GetPosition(_colorShadingCanvas); |
||||
|
UpdateColorShadeSelectorPositionAndCalculateColor(p, true); |
||||
|
Mouse.Synchronize(); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void ColorShadingCanvas_SizeChanged(object sender, SizeChangedEventArgs e) |
||||
|
{ |
||||
|
if (_currentColorPosition != null) |
||||
|
{ |
||||
|
Point _newPoint = new Point |
||||
|
{ |
||||
|
X = ((Point)_currentColorPosition).X * e.NewSize.Width, |
||||
|
Y = ((Point)_currentColorPosition).Y * e.NewSize.Height |
||||
|
}; |
||||
|
|
||||
|
UpdateColorShadeSelectorPositionAndCalculateColor(_newPoint, false); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
void SpectrumSlider_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e) |
||||
|
{ |
||||
|
if (_currentColorPosition != null) |
||||
|
{ |
||||
|
CalculateColor((Point)_currentColorPosition); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
#endregion //Event Handlers
|
||||
|
|
||||
|
#region Methods
|
||||
|
|
||||
|
private void UpdateRGBColor() |
||||
|
{ |
||||
|
SelectedColor = Color.FromArgb(A, R, G, B); |
||||
|
UpdateColorShadeSelectorPosition(SelectedColor); |
||||
|
} |
||||
|
|
||||
|
private void UpdateSelectedColor(Color color) |
||||
|
{ |
||||
|
SelectedColor = Color.FromArgb(color.A, color.R, color.G, color.B); |
||||
|
} |
||||
|
|
||||
|
private void UpdateRGBValues(Color color) |
||||
|
{ |
||||
|
A = color.A; |
||||
|
R = color.R; |
||||
|
G = color.G; |
||||
|
B = color.B; |
||||
|
} |
||||
|
|
||||
|
private void SetSelectedColorAndPositionSelector(Color color) |
||||
|
{ |
||||
|
UpdateSelectedColor(color); |
||||
|
UpdateRGBValues(color); |
||||
|
UpdateColorShadeSelectorPosition(color); |
||||
|
} |
||||
|
|
||||
|
private void UpdateColorShadeSelectorPositionAndCalculateColor(Point p, bool calculateColor) |
||||
|
{ |
||||
|
if (p.Y < 0) |
||||
|
p.Y = 0; |
||||
|
|
||||
|
if (p.X < 0) |
||||
|
p.X = 0; |
||||
|
|
||||
|
if (p.X > _colorShadingCanvas.ActualWidth) |
||||
|
p.X = _colorShadingCanvas.ActualWidth; |
||||
|
|
||||
|
if (p.Y > _colorShadingCanvas.ActualHeight) |
||||
|
p.Y = _colorShadingCanvas.ActualHeight; |
||||
|
|
||||
|
_colorShadeSelectorTransform.X = p.X - (_colorShadeSelector.Width / 2); |
||||
|
_colorShadeSelectorTransform.Y = p.Y - (_colorShadeSelector.Height / 2); |
||||
|
|
||||
|
p.X = p.X / _colorShadingCanvas.ActualWidth; |
||||
|
p.Y = p.Y / _colorShadingCanvas.ActualHeight; |
||||
|
|
||||
|
_currentColorPosition = p; |
||||
|
|
||||
|
if (calculateColor) |
||||
|
CalculateColor(p); |
||||
|
} |
||||
|
|
||||
|
private void UpdateColorShadeSelectorPosition(Color color) |
||||
|
{ |
||||
|
if (_spectrumSlider == null || _colorShadingCanvas == null) |
||||
|
return; |
||||
|
|
||||
|
_currentColorPosition = null; |
||||
|
|
||||
|
HsvColor hsv = ColorUtilities.ConvertRgbToHsv(color.R, color.G, color.B); |
||||
|
_spectrumSlider.Value = hsv.H; |
||||
|
|
||||
|
Point p = new Point(hsv.S, 1 - hsv.V); |
||||
|
|
||||
|
_currentColorPosition = p; |
||||
|
|
||||
|
_colorShadeSelectorTransform.X = (p.X * _colorShadingCanvas.Width) - 5; |
||||
|
_colorShadeSelectorTransform.Y = (p.Y * _colorShadingCanvas.Height) - 5; |
||||
|
} |
||||
|
|
||||
|
private void CalculateColor(Point p) |
||||
|
{ |
||||
|
HsvColor hsv = new HsvColor(360 - _spectrumSlider.Value, 1, 1) { S = p.X, V = 1 - p.Y }; |
||||
|
var currentColor = ColorUtilities.ConvertHsvToRgb(hsv.H, hsv.S, hsv.V); |
||||
|
currentColor.A = A; |
||||
|
SelectedColor = currentColor; |
||||
|
HexadecimalString = SelectedColor.ToString(); |
||||
|
} |
||||
|
|
||||
|
#endregion //Methods
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,86 @@ |
|||||
|
using System; |
||||
|
using System.Collections.Generic; |
||||
|
using System.Windows; |
||||
|
using System.Windows.Controls; |
||||
|
using System.Windows.Media; |
||||
|
using System.Windows.Shapes; |
||||
|
using Microsoft.Windows.Controls.Core.Utilities; |
||||
|
|
||||
|
namespace Microsoft.Windows.Controls |
||||
|
{ |
||||
|
internal class ColorSpectrumSlider : Slider |
||||
|
{ |
||||
|
#region Private Members
|
||||
|
|
||||
|
private Rectangle _spectrumDisplay; |
||||
|
private LinearGradientBrush _pickerBrush; |
||||
|
|
||||
|
#endregion //Private Members
|
||||
|
|
||||
|
#region Constructors
|
||||
|
|
||||
|
static ColorSpectrumSlider() |
||||
|
{ |
||||
|
DefaultStyleKeyProperty.OverrideMetadata(typeof(ColorSpectrumSlider), new FrameworkPropertyMetadata(typeof(ColorSpectrumSlider))); |
||||
|
} |
||||
|
|
||||
|
#endregion //Constructors
|
||||
|
|
||||
|
#region Dependency Properties
|
||||
|
|
||||
|
public static readonly DependencyProperty SelectedColorProperty = DependencyProperty.Register("SelectedColor", typeof(Color), typeof(ColorSpectrumSlider), new PropertyMetadata(System.Windows.Media.Colors.Transparent)); |
||||
|
public Color SelectedColor |
||||
|
{ |
||||
|
get { return (Color)GetValue(SelectedColorProperty); } |
||||
|
set { SetValue(SelectedColorProperty, value); } |
||||
|
} |
||||
|
|
||||
|
#endregion //Dependency Properties
|
||||
|
|
||||
|
#region Base Class Overrides
|
||||
|
|
||||
|
public override void OnApplyTemplate() |
||||
|
{ |
||||
|
base.OnApplyTemplate(); |
||||
|
|
||||
|
_spectrumDisplay = (Rectangle)GetTemplateChild("PART_SpectrumDisplay"); |
||||
|
CreateSpectrum(); |
||||
|
OnValueChanged(Double.NaN, Value); |
||||
|
} |
||||
|
|
||||
|
protected override void OnValueChanged(double oldValue, double newValue) |
||||
|
{ |
||||
|
base.OnValueChanged(oldValue, newValue); |
||||
|
|
||||
|
Color color = ColorUtilities.ConvertHsvToRgb(360 - newValue, 1, 1); |
||||
|
SelectedColor = color; |
||||
|
} |
||||
|
|
||||
|
#endregion //Base Class Overrides
|
||||
|
|
||||
|
#region Methods
|
||||
|
|
||||
|
private void CreateSpectrum() |
||||
|
{ |
||||
|
_pickerBrush = new LinearGradientBrush(); |
||||
|
_pickerBrush.StartPoint = new Point(0.5, 0); |
||||
|
_pickerBrush.EndPoint = new Point(0.5, 1); |
||||
|
_pickerBrush.ColorInterpolationMode = ColorInterpolationMode.SRgbLinearInterpolation; |
||||
|
|
||||
|
List<Color> colorsList = ColorUtilities.GenerateHsvSpectrum(); |
||||
|
|
||||
|
double stopIncrement = (double)1 / colorsList.Count; |
||||
|
|
||||
|
int i; |
||||
|
for (i = 0; i < colorsList.Count; i++) |
||||
|
{ |
||||
|
_pickerBrush.GradientStops.Add(new GradientStop(colorsList[i], i * stopIncrement)); |
||||
|
} |
||||
|
|
||||
|
_pickerBrush.GradientStops[i - 1].Offset = 1.0; |
||||
|
_spectrumDisplay.Fill = _pickerBrush; |
||||
|
} |
||||
|
|
||||
|
#endregion //Methods
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,234 @@ |
|||||
|
<ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" |
||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" |
||||
|
xmlns:local="clr-namespace:Microsoft.Windows.Controls" |
||||
|
xmlns:coreConverters="clr-namespace:Microsoft.Windows.Controls.Core.Converters"> |
||||
|
|
||||
|
<coreConverters:ColorToSolidColorBrushConverter x:Key="ColorToSolidColorBrushConverter" /> |
||||
|
|
||||
|
<LinearGradientBrush x:Key="ColorPickerDarkBorderBrush" EndPoint="0.5,1" StartPoint="0.5,0"> |
||||
|
<GradientStop Color="#FFA3AEB9" Offset="0"/> |
||||
|
<GradientStop Color="#FF8399A9" Offset="0.375"/> |
||||
|
<GradientStop Color="#FF718597" Offset="0.375"/> |
||||
|
<GradientStop Color="#FF617584" Offset="1"/> |
||||
|
</LinearGradientBrush> |
||||
|
|
||||
|
<LinearGradientBrush x:Key="PopupBackgroundBrush" StartPoint="0,0" EndPoint="0,1"> |
||||
|
<LinearGradientBrush.GradientStops> |
||||
|
<GradientStopCollection> |
||||
|
<GradientStop Offset="0" Color="#FFffffff"/> |
||||
|
<GradientStop Offset="1" Color="#FFE8EBED"/> |
||||
|
</GradientStopCollection> |
||||
|
</LinearGradientBrush.GradientStops> |
||||
|
</LinearGradientBrush> |
||||
|
|
||||
|
<DrawingBrush x:Key="CheckerBrush" Viewport="0,0,10,10" ViewportUnits="Absolute" TileMode="Tile"> |
||||
|
<DrawingBrush.Drawing> |
||||
|
<DrawingGroup> |
||||
|
<GeometryDrawing Brush="White"> |
||||
|
<GeometryDrawing.Geometry> |
||||
|
<RectangleGeometry Rect="0,0 100,100" /> |
||||
|
</GeometryDrawing.Geometry> |
||||
|
</GeometryDrawing> |
||||
|
<GeometryDrawing Brush="LightGray"> |
||||
|
<GeometryDrawing.Geometry> |
||||
|
<GeometryGroup> |
||||
|
<RectangleGeometry Rect="0,0 50,50" /> |
||||
|
<RectangleGeometry Rect="50,50 50,50" /> |
||||
|
</GeometryGroup> |
||||
|
</GeometryDrawing.Geometry> |
||||
|
</GeometryDrawing> |
||||
|
</DrawingGroup> |
||||
|
</DrawingBrush.Drawing> |
||||
|
</DrawingBrush> |
||||
|
|
||||
|
<Style TargetType="{x:Type local:ColorCanvas}"> |
||||
|
<Setter Property="BorderBrush" Value="{StaticResource ColorPickerDarkBorderBrush}" /> |
||||
|
<Setter Property="BorderThickness" Value="1" /> |
||||
|
<Setter Property="Template"> |
||||
|
<Setter.Value> |
||||
|
<ControlTemplate TargetType="{x:Type local:ColorCanvas}"> |
||||
|
<Border BorderThickness="{TemplateBinding BorderThickness}" Background="White" BorderBrush="{TemplateBinding BorderBrush}" Padding="3"> |
||||
|
<Grid Margin="2"> |
||||
|
<Grid.RowDefinitions> |
||||
|
<RowDefinition Height="Auto" /> |
||||
|
<RowDefinition Height="Auto"/> |
||||
|
</Grid.RowDefinitions> |
||||
|
<Grid> |
||||
|
<Grid.ColumnDefinitions > |
||||
|
<ColumnDefinition Width="200"></ColumnDefinition> |
||||
|
<ColumnDefinition Width="Auto"></ColumnDefinition> |
||||
|
</Grid.ColumnDefinitions> |
||||
|
<Grid.RowDefinitions> |
||||
|
<RowDefinition Height="Auto" /> |
||||
|
<RowDefinition Height="20"/> |
||||
|
</Grid.RowDefinitions> |
||||
|
|
||||
|
<Border BorderThickness="1" BorderBrush="DarkGray" ClipToBounds="True" Background="{StaticResource CheckerBrush}"> |
||||
|
<Canvas x:Name="PART_ColorShadingCanvas" Width="200" Height="100" HorizontalAlignment="Left" VerticalAlignment="Top"> |
||||
|
<Rectangle x:Name="ColorShadingRectangle" Height="{Binding ElementName=PART_ColorShadingCanvas,Path=Height}" Width="{Binding ElementName=PART_ColorShadingCanvas,Path=Width}" |
||||
|
Fill="{Binding SelectedColor, ElementName=PART_SpectrumSlider, Converter={StaticResource ColorToSolidColorBrushConverter}}" /> |
||||
|
<Rectangle x:Name="WhiteGradient" Width="{Binding ElementName=PART_ColorShadingCanvas,Path=Width}" Height="{Binding ElementName=PART_ColorShadingCanvas,Path=Height}" > |
||||
|
<Rectangle.Fill> |
||||
|
<LinearGradientBrush StartPoint="0,0" EndPoint="1,0"> |
||||
|
<GradientStop Offset="0" Color="#ffffffff"/> |
||||
|
<GradientStop Offset="1" Color="Transparent"/> |
||||
|
</LinearGradientBrush> |
||||
|
</Rectangle.Fill> |
||||
|
</Rectangle> |
||||
|
<Rectangle x:Name="BlackGradient" Width="{Binding ElementName=PART_ColorShadingCanvas,Path=Width}" Height="{Binding ElementName=PART_ColorShadingCanvas,Path=Height}" > |
||||
|
<Rectangle.Fill> |
||||
|
<LinearGradientBrush StartPoint="0,1" EndPoint="0, 0"> |
||||
|
<GradientStop Offset="0" Color="#ff000000"/> |
||||
|
<GradientStop Offset="1" Color="#00000000"/> |
||||
|
</LinearGradientBrush> |
||||
|
</Rectangle.Fill> |
||||
|
</Rectangle> |
||||
|
<Canvas x:Name="PART_ColorShadeSelector" Width="10" Height="10" IsHitTestVisible="False"> |
||||
|
<Ellipse Width="10" Height="10" StrokeThickness="3" Stroke="#FFFFFFFF" IsHitTestVisible="False" /> |
||||
|
<Ellipse Width="10" Height="10" StrokeThickness="1" Stroke="#FF000000" IsHitTestVisible="False" /> |
||||
|
</Canvas> |
||||
|
</Canvas> |
||||
|
</Border> |
||||
|
|
||||
|
<Border BorderThickness="0,1,0,0" Grid.Row="1"> |
||||
|
<Grid Background="{StaticResource CheckerBrush}"> |
||||
|
<Rectangle x:Name="SelectedColor" Fill="{Binding SelectedColor, RelativeSource={RelativeSource TemplatedParent}, Converter={StaticResource ColorToSolidColorBrushConverter}}" /> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
|
||||
|
<Border Grid.Column="1" Grid.RowSpan="2" Margin="4,-8,0,0" ClipToBounds="False"> |
||||
|
<local:ColorSpectrumSlider x:Name="PART_SpectrumSlider" VerticalAlignment="Stretch" /> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
|
||||
|
<Border MinWidth="180" Grid.Row="1" BorderThickness="1" ClipToBounds="True" Margin="0,10,0,0"> |
||||
|
<Grid> |
||||
|
<Grid.RowDefinitions> |
||||
|
<RowDefinition Height="Auto"/> |
||||
|
<RowDefinition Height="Auto"/> |
||||
|
<RowDefinition Height="Auto"/> |
||||
|
<RowDefinition Height="Auto"/> |
||||
|
</Grid.RowDefinitions> |
||||
|
<Grid.ColumnDefinitions> |
||||
|
<ColumnDefinition Width="Auto"/> |
||||
|
<ColumnDefinition Width="*"/> |
||||
|
<ColumnDefinition Width="Auto"/> |
||||
|
</Grid.ColumnDefinitions> |
||||
|
|
||||
|
<TextBlock Grid.Row="0" Grid.Column="0" Text="R" /> |
||||
|
<Slider x:Name="PART_RSlider" Maximum="255" TickFrequency="1" Grid.Row="0" Grid.Column="1" |
||||
|
Value="{Binding R, RelativeSource={RelativeSource TemplatedParent}}"/> |
||||
|
<TextBox Grid.Row="0" Grid.Column="2" Text="{Binding Value, ElementName=PART_RSlider}" /> |
||||
|
|
||||
|
<TextBlock Grid.Row="1" Grid.Column="0" Text="G" /> |
||||
|
<Slider x:Name="PART_GSlider" Maximum="255" TickFrequency="1" Grid.Row="1" Grid.Column="1" |
||||
|
Value="{Binding G, RelativeSource={RelativeSource TemplatedParent}}"/> |
||||
|
<TextBox Grid.Row="1" Grid.Column="2" Text="{Binding Value, ElementName=PART_GSlider}" /> |
||||
|
|
||||
|
<TextBlock Grid.Row="2" Grid.Column="0" Text="B" /> |
||||
|
<Slider x:Name="PART_BSlider" Maximum="255" TickFrequency="1" Grid.Row="2" Grid.Column="1" |
||||
|
Value="{Binding B, RelativeSource={RelativeSource TemplatedParent}}"/> |
||||
|
<TextBox Grid.Row="2" Grid.Column="3" Text="{Binding Value, ElementName=PART_BSlider}" /> |
||||
|
|
||||
|
<TextBlock Grid.Row="3" Grid.Column="0" Text="A" /> |
||||
|
<Slider x:Name="PART_OpacitySlider" Grid.Row="3" Grid.Column="1" Maximum="255" |
||||
|
Value="{Binding Path=A, RelativeSource={RelativeSource TemplatedParent}}"/> |
||||
|
<TextBox Grid.Row="3" Grid.Column="3" Text="{Binding Value, ElementName=PART_OpacitySlider}" /> |
||||
|
|
||||
|
</Grid> |
||||
|
</Border> |
||||
|
</Grid> |
||||
|
</Border> |
||||
|
</ControlTemplate> |
||||
|
</Setter.Value> |
||||
|
</Setter> |
||||
|
</Style> |
||||
|
|
||||
|
<Style x:Key="SliderRepeatButtonStyle" |
||||
|
TargetType="{x:Type RepeatButton}"> |
||||
|
<Setter Property="OverridesDefaultStyle" Value="true"/> |
||||
|
<Setter Property="IsTabStop" Value="false"/> |
||||
|
<Setter Property="Focusable" Value="false"/> |
||||
|
<Setter Property="Background" Value="Transparent"/> |
||||
|
<Setter Property="Template"> |
||||
|
<Setter.Value> |
||||
|
<ControlTemplate TargetType="{x:Type RepeatButton}"> |
||||
|
<Border Background="{TemplateBinding Background}"/> |
||||
|
</ControlTemplate> |
||||
|
</Setter.Value> |
||||
|
</Setter> |
||||
|
</Style> |
||||
|
|
||||
|
<Style x:Key="VerticalSlideThumbStyle" TargetType="{x:Type Thumb}"> |
||||
|
<Setter Property="Focusable" Value="false"/> |
||||
|
<Setter Property="OverridesDefaultStyle" Value="true"/> |
||||
|
<Setter Property="Height" Value="12"/> |
||||
|
<Setter Property="Width" Value="11"/> |
||||
|
<Setter Property="Foreground" Value="Gray"/> |
||||
|
<Setter Property="Template"> |
||||
|
<Setter.Value> |
||||
|
<ControlTemplate TargetType="{x:Type Thumb}"> |
||||
|
<Canvas SnapsToDevicePixels="true"> |
||||
|
<Path x:Name="LeftArrow" Stretch="Fill" StrokeLineJoin="Round" Stroke="#FF000000" Fill="#FF000000" Data="F1 M 276.761,316L 262.619,307.835L 262.619,324.165L 276.761,316 Z " RenderTransformOrigin="0.5,0.5" Width="6" Height="8" > |
||||
|
<Path.RenderTransform> |
||||
|
<TransformGroup> |
||||
|
<ScaleTransform/> |
||||
|
<SkewTransform/> |
||||
|
<RotateTransform /> |
||||
|
<TranslateTransform Y="6" X="-3"/> |
||||
|
</TransformGroup> |
||||
|
</Path.RenderTransform> |
||||
|
</Path> |
||||
|
<Path x:Name="RightArrow" Stretch="Fill" StrokeLineJoin="Round" Stroke="#FF000000" Fill="#FF000000" Data="F1 M 276.761,316L 262.619,307.835L 262.619,324.165L 276.761,316 Z " RenderTransformOrigin="0.5,0.5" Width="6" Height="8" > |
||||
|
<Path.RenderTransform> |
||||
|
<TransformGroup> |
||||
|
<ScaleTransform/> |
||||
|
<SkewTransform/> |
||||
|
<RotateTransform Angle="-180"/> |
||||
|
<TranslateTransform Y="6" X="8"/> |
||||
|
</TransformGroup> |
||||
|
</Path.RenderTransform> |
||||
|
</Path> |
||||
|
</Canvas> |
||||
|
</ControlTemplate> |
||||
|
</Setter.Value> |
||||
|
</Setter> |
||||
|
</Style> |
||||
|
|
||||
|
<Style TargetType="{x:Type local:ColorSpectrumSlider}"> |
||||
|
<Setter Property="Orientation" Value="Vertical"/> |
||||
|
<Setter Property="Background" Value="Transparent"/> |
||||
|
<Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/> |
||||
|
<Setter Property="Minimum" Value="1"/> |
||||
|
<Setter Property="Maximum" Value="360"/> |
||||
|
<Setter Property="TickFrequency" Value="0.001" /> |
||||
|
<Setter Property="IsSnapToTickEnabled" Value="True" /> |
||||
|
<Setter Property="IsDirectionReversed" Value="False" /> |
||||
|
<Setter Property="IsMoveToPointEnabled" Value="True" /> |
||||
|
<Setter Property="Value" Value="360" /> |
||||
|
<Setter Property="Template"> |
||||
|
<Setter.Value> |
||||
|
<ControlTemplate TargetType="{x:Type local:ColorSpectrumSlider}"> |
||||
|
<Grid> |
||||
|
<Border x:Name="PART_TrackBackground" BorderBrush="DarkGray" BorderThickness="1" Width="15" Margin="0,8,0,0" > |
||||
|
<Rectangle x:Name="PART_SpectrumDisplay" Stretch="Fill" VerticalAlignment="Stretch" /> |
||||
|
</Border> |
||||
|
|
||||
|
<Track Name="PART_Track"> |
||||
|
<Track.DecreaseRepeatButton> |
||||
|
<RepeatButton Style="{StaticResource SliderRepeatButtonStyle}" Command="Slider.DecreaseLarge"/> |
||||
|
</Track.DecreaseRepeatButton> |
||||
|
<Track.IncreaseRepeatButton> |
||||
|
<RepeatButton Style="{StaticResource SliderRepeatButtonStyle}" Command="Slider.IncreaseLarge"/> |
||||
|
</Track.IncreaseRepeatButton> |
||||
|
<Track.Thumb> |
||||
|
<Thumb Style="{StaticResource VerticalSlideThumbStyle}" /> |
||||
|
</Track.Thumb> |
||||
|
</Track> |
||||
|
</Grid> |
||||
|
</ControlTemplate> |
||||
|
</Setter.Value> |
||||
|
</Setter> |
||||
|
</Style> |
||||
|
|
||||
|
</ResourceDictionary> |
||||
@ -1,24 +0,0 @@ |
|||||
using System; |
|
||||
using System.Linq; |
|
||||
using System.Windows.Media; |
|
||||
using System.Reflection; |
|
||||
using System.Collections.Generic; |
|
||||
|
|
||||
namespace Microsoft.Windows.Controls |
|
||||
{ |
|
||||
static class ColorUtilities |
|
||||
{ |
|
||||
public static readonly Dictionary<string, Color> KnownColors = GetKnownColors(); |
|
||||
|
|
||||
public static string GetColorName(this Color color) |
|
||||
{ |
|
||||
return KnownColors.Where(kvp => kvp.Value.Equals(color)).Select(kvp => kvp.Key).FirstOrDefault(); |
|
||||
} |
|
||||
|
|
||||
private static Dictionary<string, Color> GetKnownColors() |
|
||||
{ |
|
||||
var colorProperties = typeof(Colors).GetProperties(BindingFlags.Static | BindingFlags.Public); |
|
||||
return colorProperties.ToDictionary(p => p.Name, p => (Color)p.GetValue(null, null)); |
|
||||
} |
|
||||
} |
|
||||
} |
|
||||
@ -0,0 +1,33 @@ |
|||||
|
using System; |
||||
|
using System.Windows.Data; |
||||
|
using System.Windows.Media; |
||||
|
|
||||
|
namespace Microsoft.Windows.Controls.Core.Converters |
||||
|
{ |
||||
|
public class SolidColorBrushToColorConverter : IValueConverter |
||||
|
{ |
||||
|
#region IValueConverter Members
|
||||
|
|
||||
|
public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) |
||||
|
{ |
||||
|
SolidColorBrush brush = value as SolidColorBrush; |
||||
|
if (brush != null) |
||||
|
return brush.Color; |
||||
|
|
||||
|
return default(Color); |
||||
|
} |
||||
|
|
||||
|
public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture) |
||||
|
{ |
||||
|
if (value != null) |
||||
|
{ |
||||
|
Color color = (Color)value; |
||||
|
return new SolidColorBrush(color); |
||||
|
} |
||||
|
|
||||
|
return default(SolidColorBrush); |
||||
|
} |
||||
|
|
||||
|
#endregion
|
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,18 @@ |
|||||
|
using System; |
||||
|
|
||||
|
namespace Microsoft.Windows.Controls.Primitives |
||||
|
{ |
||||
|
internal struct HsvColor |
||||
|
{ |
||||
|
public double H; |
||||
|
public double S; |
||||
|
public double V; |
||||
|
|
||||
|
public HsvColor(double h, double s, double v) |
||||
|
{ |
||||
|
H = h; |
||||
|
S = s; |
||||
|
V = v; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
@ -0,0 +1,172 @@ |
|||||
|
using System; |
||||
|
using System.Linq; |
||||
|
using System.Windows.Media; |
||||
|
using System.Reflection; |
||||
|
using System.Collections.Generic; |
||||
|
using Microsoft.Windows.Controls.Primitives; |
||||
|
|
||||
|
namespace Microsoft.Windows.Controls.Core.Utilities |
||||
|
{ |
||||
|
static class ColorUtilities |
||||
|
{ |
||||
|
public static readonly Dictionary<string, Color> KnownColors = GetKnownColors(); |
||||
|
|
||||
|
public static string GetColorName(this Color color) |
||||
|
{ |
||||
|
return KnownColors.Where(kvp => kvp.Value.Equals(color)).Select(kvp => kvp.Key).FirstOrDefault(); |
||||
|
} |
||||
|
|
||||
|
private static Dictionary<string, Color> GetKnownColors() |
||||
|
{ |
||||
|
var colorProperties = typeof(Colors).GetProperties(BindingFlags.Static | BindingFlags.Public); |
||||
|
return colorProperties.ToDictionary(p => p.Name, p => (Color)p.GetValue(null, null)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Converts an RGB color to an HSV color.
|
||||
|
/// </summary>
|
||||
|
/// <param name="r"></param>
|
||||
|
/// <param name="b"></param>
|
||||
|
/// <param name="g"></param>
|
||||
|
/// <returns></returns>
|
||||
|
public static HsvColor ConvertRgbToHsv(int r, int b, int g) |
||||
|
{ |
||||
|
double delta, min; |
||||
|
double h = 0, s, v; |
||||
|
|
||||
|
min = Math.Min(Math.Min(r, g), b); |
||||
|
v = Math.Max(Math.Max(r, g), b); |
||||
|
delta = v - min; |
||||
|
|
||||
|
if (v == 0.0) |
||||
|
{ |
||||
|
s = 0; |
||||
|
} |
||||
|
else |
||||
|
s = delta / v; |
||||
|
|
||||
|
if (s == 0) |
||||
|
h = 0.0; |
||||
|
|
||||
|
else |
||||
|
{ |
||||
|
if (r == v) |
||||
|
h = (g - b) / delta; |
||||
|
else if (g == v) |
||||
|
h = 2 + (b - r) / delta; |
||||
|
else if (b == v) |
||||
|
h = 4 + (r - g) / delta; |
||||
|
|
||||
|
h *= 60; |
||||
|
if (h < 0.0) |
||||
|
h = h + 360; |
||||
|
|
||||
|
} |
||||
|
|
||||
|
return new HsvColor { H = h, S = s, V = v / 255 }; |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Converts an HSV color to an RGB color.
|
||||
|
/// </summary>
|
||||
|
/// <param name="h"></param>
|
||||
|
/// <param name="s"></param>
|
||||
|
/// <param name="v"></param>
|
||||
|
/// <returns></returns>
|
||||
|
public static Color ConvertHsvToRgb(double h, double s, double v) |
||||
|
{ |
||||
|
double r = 0, g = 0, b = 0; |
||||
|
|
||||
|
if (s == 0) |
||||
|
{ |
||||
|
r = v; |
||||
|
g = v; |
||||
|
b = v; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
int i; |
||||
|
double f, p, q, t; |
||||
|
|
||||
|
if (h == 360) |
||||
|
h = 0; |
||||
|
else |
||||
|
h = h / 60; |
||||
|
|
||||
|
i = (int)Math.Truncate(h); |
||||
|
f = h - i; |
||||
|
|
||||
|
p = v * (1.0 - s); |
||||
|
q = v * (1.0 - (s * f)); |
||||
|
t = v * (1.0 - (s * (1.0 - f))); |
||||
|
|
||||
|
switch (i) |
||||
|
{ |
||||
|
case 0: |
||||
|
{ |
||||
|
r = v; |
||||
|
g = t; |
||||
|
b = p; |
||||
|
break; |
||||
|
} |
||||
|
case 1: |
||||
|
{ |
||||
|
r = q; |
||||
|
g = v; |
||||
|
b = p; |
||||
|
break; |
||||
|
} |
||||
|
case 2: |
||||
|
{ |
||||
|
r = p; |
||||
|
g = v; |
||||
|
b = t; |
||||
|
break; |
||||
|
} |
||||
|
case 3: |
||||
|
{ |
||||
|
r = p; |
||||
|
g = q; |
||||
|
b = v; |
||||
|
break; |
||||
|
} |
||||
|
case 4: |
||||
|
{ |
||||
|
r = t; |
||||
|
g = p; |
||||
|
b = v; |
||||
|
break; |
||||
|
} |
||||
|
default: |
||||
|
{ |
||||
|
r = v; |
||||
|
g = p; |
||||
|
b = q; |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
} |
||||
|
|
||||
|
return Color.FromArgb(255, (byte)(r * 255), (byte)(g * 255), (byte)(b * 255)); |
||||
|
} |
||||
|
|
||||
|
/// <summary>
|
||||
|
/// Generates a list of colors with hues ranging from 0 360 and a saturation and value of 1.
|
||||
|
/// </summary>
|
||||
|
/// <returns></returns>
|
||||
|
public static List<Color> GenerateHsvSpectrum() |
||||
|
{ |
||||
|
List<Color> colorsList = new List<Color>(8); |
||||
|
|
||||
|
for (int i = 0; i < 29; i++) |
||||
|
{ |
||||
|
colorsList.Add(ColorUtilities.ConvertHsvToRgb(i * 12, 1, 1)); |
||||
|
} |
||||
|
|
||||
|
colorsList.Add(ColorUtilities.ConvertHsvToRgb(0, 1, 1)); |
||||
|
|
||||
|
return colorsList; |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue