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