mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-04 18:26:39 +02:00
[ColorPicker] CMYK, HSV and HSL color format (#6975)
* Add HSL and HSV color formats + cleanup + docu * Fix build problem (lang version) * Add CYMK color + replace float with double values * ups - fix cmyk text format * fix wrong settings text + doc typo fix * Address feedback * Address feedback + fix to small window size * adress feedback + more cleanup * typo fix * Avoid possible division by zero + unit test * Address feedback - move all represenation to own helper class + UnitTest * Address feedback -> switch to mstest framework
This commit is contained in:
@@ -6,6 +6,7 @@ using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Interactivity;
|
||||
using System.Windows.Media.Animation;
|
||||
using ColorPicker.Constants;
|
||||
|
||||
namespace ColorPicker.Behaviors
|
||||
{
|
||||
@@ -37,21 +38,31 @@ namespace ColorPicker.Behaviors
|
||||
|
||||
private void Appear()
|
||||
{
|
||||
var opacityAppear = new DoubleAnimation(0, 1.0, new Duration(TimeSpan.FromMilliseconds(250)));
|
||||
opacityAppear.EasingFunction = new QuadraticEase() { EasingMode = EasingMode.EaseOut };
|
||||
var duration = new Duration(TimeSpan.FromMilliseconds(250));
|
||||
|
||||
var resize = new DoubleAnimation(0, 180, new Duration(TimeSpan.FromMilliseconds(250)));
|
||||
resize.EasingFunction = new ExponentialEase() { EasingMode = EasingMode.EaseOut };
|
||||
AssociatedObject.BeginAnimation(Window.OpacityProperty, opacityAppear);
|
||||
AssociatedObject.BeginAnimation(Window.WidthProperty, resize);
|
||||
var opacityAppear = new DoubleAnimation(0d, 1d, duration)
|
||||
{
|
||||
EasingFunction = new QuadraticEase() { EasingMode = EasingMode.EaseOut },
|
||||
};
|
||||
|
||||
var resize = new DoubleAnimation(0d, WindowConstant.PickerWindowWidth, duration)
|
||||
{
|
||||
EasingFunction = new ExponentialEase() { EasingMode = EasingMode.EaseOut },
|
||||
};
|
||||
|
||||
AssociatedObject.BeginAnimation(UIElement.OpacityProperty, opacityAppear);
|
||||
AssociatedObject.BeginAnimation(FrameworkElement.WidthProperty, resize);
|
||||
}
|
||||
|
||||
private void Hide()
|
||||
{
|
||||
var opacityAppear = new DoubleAnimation(0, new Duration(TimeSpan.FromMilliseconds(1)));
|
||||
var resize = new DoubleAnimation(0, new Duration(TimeSpan.FromMilliseconds(1)));
|
||||
AssociatedObject.BeginAnimation(Window.OpacityProperty, opacityAppear);
|
||||
AssociatedObject.BeginAnimation(Window.WidthProperty, resize);
|
||||
var duration = new Duration(TimeSpan.FromMilliseconds(1));
|
||||
|
||||
var opacityAppear = new DoubleAnimation(0d, duration);
|
||||
var resize = new DoubleAnimation(0d, duration);
|
||||
|
||||
AssociatedObject.BeginAnimation(UIElement.OpacityProperty, opacityAppear);
|
||||
AssociatedObject.BeginAnimation(FrameworkElement.WidthProperty, resize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
|
||||
using System.ComponentModel.Composition;
|
||||
using System.ComponentModel.Composition.Hosting;
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("UnitTest-ColorPickerUI")]
|
||||
|
||||
namespace ColorPicker
|
||||
{
|
||||
@@ -21,8 +24,6 @@ namespace ColorPicker
|
||||
}
|
||||
|
||||
public static void Dispose()
|
||||
{
|
||||
Container.Dispose();
|
||||
}
|
||||
=> Container.Dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||
<DebugType>full</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<LangVersion>9.0</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
@@ -73,7 +73,7 @@
|
||||
<Optimize>true</Optimize>
|
||||
<DebugType>pdbonly</DebugType>
|
||||
<PlatformTarget>x64</PlatformTarget>
|
||||
<LangVersion>7.3</LangVersion>
|
||||
<LangVersion>9.0</LangVersion>
|
||||
<ErrorReport>prompt</ErrorReport>
|
||||
<CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
|
||||
<Prefer32Bit>true</Prefer32Bit>
|
||||
@@ -107,6 +107,9 @@
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Compile Include="Behaviors\GridEffectBehavior.cs" />
|
||||
<Compile Include="Constants\WindowConstant.cs" />
|
||||
<Compile Include="Helpers\ColorHelper.cs" />
|
||||
<Compile Include="Helpers\ColorRepresentationHelper.cs" />
|
||||
<Compile Include="Helpers\IThrottledActionInvoker.cs" />
|
||||
<Compile Include="Helpers\ThrottledActionInvoker.cs" />
|
||||
<Compile Include="NativeMethods.cs" />
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
namespace ColorPicker.Constants
|
||||
{
|
||||
/// <summary>
|
||||
/// This class contains all assembly wide constants for windows and views
|
||||
/// </summary>
|
||||
public static class WindowConstant
|
||||
{
|
||||
/// <summary>
|
||||
/// The width of the color picker window
|
||||
/// </summary>
|
||||
public const double PickerWindowWidth = 240d;
|
||||
}
|
||||
}
|
||||
84
src/modules/colorPicker/ColorPickerUI/Helpers/ColorHelper.cs
Normal file
84
src/modules/colorPicker/ColorPickerUI/Helpers/ColorHelper.cs
Normal file
@@ -0,0 +1,84 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
|
||||
namespace ColorPicker.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to easier work with colors
|
||||
/// </summary>
|
||||
internal static class ColorHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Convert a given <see cref="Color"/> color to a HSL color (hue, saturation, lightness)
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="Color"/> to convert</param>
|
||||
/// <returns>The hue [0°..360°], saturation [0..1] and lightness [0..1] values of the converted color</returns>
|
||||
internal static (double hue, double saturation, double lightness) ConvertToHSLColor(Color color)
|
||||
{
|
||||
var min = Math.Min(Math.Min(color.R, color.G), color.B) / 255d;
|
||||
var max = Math.Max(Math.Max(color.R, color.G), color.B) / 255d;
|
||||
|
||||
var lightness = (max + min) / 2d;
|
||||
|
||||
if (lightness == 0d || min == max)
|
||||
{
|
||||
return (color.GetHue(), 0d, lightness);
|
||||
}
|
||||
else if (lightness is > 0d and <= 0.5d)
|
||||
{
|
||||
return (color.GetHue(), (max - min) / (max + min), lightness);
|
||||
}
|
||||
|
||||
return (color.GetHue(), (max - min) / (2d - (max + min)), lightness);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a given <see cref="Color"/> color to a HSV color (hue, saturation, value)
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="Color"/> to convert</param>
|
||||
/// <returns>The hue [0°..360°], saturation [0..1] and value [0..1] of the converted color</returns>
|
||||
internal static (double hue, double saturation, double value) ConvertToHSVColor(Color color)
|
||||
{
|
||||
var min = Math.Min(Math.Min(color.R, color.G), color.B) / 255d;
|
||||
var max = Math.Max(Math.Max(color.R, color.G), color.B) / 255d;
|
||||
|
||||
return (color.GetHue(), max == 0d ? 0d : (max - min) / max, max);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Convert a given <see cref="Color"/> color to a CYMK color (cyan, magenta, yellow, black key)
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="Color"/> to convert</param>
|
||||
/// <returns>The cyan[0..1], magenta[0..1], yellow[0..1] and black key[0..1] of the converted color</returns>
|
||||
internal static (double cyan, double magenta, double yellow, double blackKey) ConvertToCMYKColor(Color color)
|
||||
{
|
||||
// special case for black (avoid division by zero)
|
||||
if (color.R == 0 && color.G == 0 && color.B == 0)
|
||||
{
|
||||
return (0d, 0d, 0d, 1d);
|
||||
}
|
||||
|
||||
var red = color.R / 255d;
|
||||
var green = color.G / 255d;
|
||||
var blue = color.B / 255d;
|
||||
|
||||
var blackKey = 1d - Math.Max(Math.Max(red, green), blue);
|
||||
|
||||
// special case for black (avoid division by zero)
|
||||
if (1d - blackKey == 0d)
|
||||
{
|
||||
return (0d, 0d, 0d, 1d);
|
||||
}
|
||||
|
||||
var cyan = (1d - red - blackKey) / (1d - blackKey);
|
||||
var magenta = (1d - green - blackKey) / (1d - blackKey);
|
||||
var yellow = (1d - blue - blackKey) / (1d - blackKey);
|
||||
|
||||
return (cyan, magenta, yellow, blackKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
// Copyright (c) Microsoft Corporation
|
||||
// The Microsoft Corporation licenses this file to you under the MIT license.
|
||||
// See the LICENSE file in the project root for more information.
|
||||
|
||||
using System;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using Microsoft.PowerToys.Settings.UI.Lib;
|
||||
|
||||
namespace ColorPicker.Helpers
|
||||
{
|
||||
/// <summary>
|
||||
/// Helper class to easier work with color represantation
|
||||
/// </summary>
|
||||
internal static class ColorRepresentationHelper
|
||||
{
|
||||
/// <summary>
|
||||
/// Return a <see cref="string"/> representation of a given <see cref="Color"/>
|
||||
/// </summary>
|
||||
/// <param name="color">The <see cref="Color"/> for the presentation</param>
|
||||
/// <param name="colorRepresentationType">The type of the representation</param>
|
||||
/// <returns>A <see cref="string"/> representation of a color</returns>
|
||||
internal static string GetStringRepresentation(Color color, ColorRepresentationType colorRepresentationType)
|
||||
=> colorRepresentationType switch
|
||||
{
|
||||
ColorRepresentationType.CMYK => ColorToCYMK(color),
|
||||
ColorRepresentationType.HEX => ColorToHex(color),
|
||||
ColorRepresentationType.HSL => ColorToHSL(color),
|
||||
ColorRepresentationType.HSV => ColorToHSV(color),
|
||||
ColorRepresentationType.RGB => ColorToRGB(color),
|
||||
|
||||
// Fall-back value, when "_userSettings.CopiedColorRepresentation.Value" is incorrect
|
||||
_ => ColorToHex(color),
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Return a hexadecimal <see cref="string"/> representation of a RGB color
|
||||
/// </summary>
|
||||
/// <param name="color">The see cref="Color"/> for the hexadecimal presentation</param>
|
||||
/// <returns>A hexadecimal <see cref="string"/> representation of a RGB color</returns>
|
||||
private static string ColorToHex(Color color)
|
||||
=> $"#{color.R.ToString("X2", CultureInfo.InvariantCulture)}"
|
||||
+ $"{color.G.ToString("X2", CultureInfo.InvariantCulture)}"
|
||||
+ $"{color.B.ToString("X2", CultureInfo.InvariantCulture)}";
|
||||
|
||||
/// <summary>
|
||||
/// Return a <see cref="string"/> representation of a RGB color
|
||||
/// </summary>
|
||||
/// <param name="color">The see cref="Color"/> for the RGB color presentation</param>
|
||||
/// <returns>A <see cref="string"/> representation of a RGB color</returns>
|
||||
private static string ColorToRGB(Color color)
|
||||
=> $"rgb({color.R.ToString(CultureInfo.InvariantCulture)}"
|
||||
+ $", {color.G.ToString(CultureInfo.InvariantCulture)}"
|
||||
+ $", {color.B.ToString(CultureInfo.InvariantCulture)})";
|
||||
|
||||
/// <summary>
|
||||
/// Return a <see cref="string"/> representation of a HSL color
|
||||
/// </summary>
|
||||
/// <param name="color">The see cref="Color"/> for the HSL color presentation</param>
|
||||
/// <returns>A <see cref="string"/> representation of a HSL color</returns>
|
||||
private static string ColorToHSL(Color color)
|
||||
{
|
||||
var (hue, saturation, lightness) = ColorHelper.ConvertToHSLColor(color);
|
||||
|
||||
hue = Math.Round(hue);
|
||||
saturation = Math.Round(saturation * 100);
|
||||
lightness = Math.Round(lightness * 100);
|
||||
|
||||
return $"hsl({hue.ToString(CultureInfo.InvariantCulture)}"
|
||||
+ $", {saturation.ToString(CultureInfo.InvariantCulture)}%"
|
||||
+ $", {lightness.ToString(CultureInfo.InvariantCulture)}%)";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a <see cref="string"/> representation of a HSV color
|
||||
/// </summary>
|
||||
/// <param name="color">The see cref="Color"/> for the HSV color presentation</param>
|
||||
/// <returns>A <see cref="string"/> representation of a HSV color</returns>
|
||||
private static string ColorToHSV(Color color)
|
||||
{
|
||||
var (hue, saturation, value) = ColorHelper.ConvertToHSVColor(color);
|
||||
|
||||
hue = Math.Round(hue);
|
||||
saturation = Math.Round(saturation * 100);
|
||||
value = Math.Round(value * 100);
|
||||
|
||||
return $"hsv({hue.ToString(CultureInfo.InvariantCulture)}"
|
||||
+ $", {saturation.ToString(CultureInfo.InvariantCulture)}%"
|
||||
+ $", {value.ToString(CultureInfo.InvariantCulture)}%)";
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Return a <see cref="string"/> representation of a HSV color
|
||||
/// </summary>
|
||||
/// <param name="color">The see cref="Color"/> for the HSV color presentation</param>
|
||||
/// <returns>A <see cref="string"/> representation of a HSV color</returns>
|
||||
private static string ColorToCYMK(Color color)
|
||||
{
|
||||
var (cyan, magenta, yellow, blackKey) = ColorHelper.ConvertToCMYKColor(color);
|
||||
|
||||
cyan = Math.Round(cyan * 100);
|
||||
magenta = Math.Round(magenta * 100);
|
||||
yellow = Math.Round(yellow * 100);
|
||||
blackKey = Math.Round(blackKey * 100);
|
||||
|
||||
return $"cmyk({cyan.ToString(CultureInfo.InvariantCulture)}%"
|
||||
+ $", {magenta.ToString(CultureInfo.InvariantCulture)}%"
|
||||
+ $", {yellow.ToString(CultureInfo.InvariantCulture)}%"
|
||||
+ $", {blackKey.ToString(CultureInfo.InvariantCulture)}%)";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,11 @@
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:ColorPickerUI"
|
||||
xmlns:constants="clr-namespace:ColorPicker.Constants"
|
||||
mc:Ignorable="d"
|
||||
xmlns:e="http://schemas.microsoft.com/expression/2010/interactivity"
|
||||
xmlns:behaviors="clr-namespace:ColorPicker.Behaviors"
|
||||
Title="Color Picker" Height="50" Width="180" WindowStyle="None" Opacity="0.01" ShowInTaskbar="False" ResizeMode="NoResize" Topmost="True" Background="Transparent" AllowsTransparency="True">
|
||||
Title="Color Picker" Height="50" Width="{x:Static constants:WindowConstant.PickerWindowWidth}" WindowStyle="None" Opacity="0.01" ShowInTaskbar="False" ResizeMode="NoResize" Topmost="True" Background="Transparent" AllowsTransparency="True">
|
||||
<e:Interaction.Behaviors>
|
||||
<behaviors:ChangeWindowPositionBehavior/>
|
||||
<behaviors:AppearAnimationBehavior/>
|
||||
|
||||
@@ -8,10 +8,14 @@ namespace ColorPicker.ViewModelContracts
|
||||
{
|
||||
public interface IMainViewModel
|
||||
{
|
||||
string HexColor { get; }
|
||||
|
||||
string RgbColor { get; }
|
||||
/// <summary>
|
||||
/// Gets the text representation of the selected color value
|
||||
/// </summary>
|
||||
string ColorText { get; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current selected color as a <see cref="Brush"/>
|
||||
/// </summary>
|
||||
Brush ColorBrush { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
|
||||
using System;
|
||||
using System.ComponentModel.Composition;
|
||||
using System.Globalization;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using ColorPicker.Common;
|
||||
@@ -23,11 +23,23 @@ namespace ColorPicker.ViewModels
|
||||
[Export(typeof(IMainViewModel))]
|
||||
public class MainViewModel : ViewModelBase, IMainViewModel
|
||||
{
|
||||
/// <summary>
|
||||
/// Defined error code for "clipboard can't open"
|
||||
/// </summary>
|
||||
private const uint ErrorCodeClipboardCantOpen = 0x800401D0;
|
||||
|
||||
private readonly ZoomWindowHelper _zoomWindowHelper;
|
||||
private readonly AppStateHandler _appStateHandler;
|
||||
private readonly IUserSettings _userSettings;
|
||||
private string _hexColor;
|
||||
private string _rgbColor;
|
||||
|
||||
/// <summary>
|
||||
/// Backing field for <see cref="OtherColor"/>
|
||||
/// </summary>
|
||||
private string _colorText;
|
||||
|
||||
/// <summary>
|
||||
/// Backing field for <see cref="ColorBrush"/>
|
||||
/// </summary>
|
||||
private Brush _colorBrush;
|
||||
|
||||
[ImportingConstructor]
|
||||
@@ -52,41 +64,12 @@ namespace ColorPicker.ViewModels
|
||||
keyboardMonitor?.Start();
|
||||
}
|
||||
|
||||
public string HexColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return _hexColor;
|
||||
}
|
||||
|
||||
private set
|
||||
{
|
||||
_hexColor = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
public string RgbColor
|
||||
{
|
||||
get
|
||||
{
|
||||
return _rgbColor;
|
||||
}
|
||||
|
||||
private set
|
||||
{
|
||||
_rgbColor = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the current selected color as a <see cref="Brush"/>
|
||||
/// </summary>
|
||||
public Brush ColorBrush
|
||||
{
|
||||
get
|
||||
{
|
||||
return _colorBrush;
|
||||
}
|
||||
|
||||
get => _colorBrush;
|
||||
private set
|
||||
{
|
||||
_colorBrush = value;
|
||||
@@ -94,74 +77,80 @@ namespace ColorPicker.ViewModels
|
||||
}
|
||||
}
|
||||
|
||||
private void Mouse_ColorChanged(object sender, System.Drawing.Color color)
|
||||
/// <summary>
|
||||
/// Gets the text representation of the selected color value
|
||||
/// </summary>
|
||||
public string ColorText
|
||||
{
|
||||
HexColor = ColorToHex(color);
|
||||
RgbColor = ColorToRGB(color);
|
||||
ColorBrush = new SolidColorBrush(Color.FromArgb(color.A, color.R, color.G, color.B));
|
||||
get => _colorText;
|
||||
private set
|
||||
{
|
||||
_colorText = value;
|
||||
OnPropertyChanged();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tell the color picker that the color on the position of the mouse cursor have changed
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender of this event</param>
|
||||
/// <param name="color">The new <see cref="Color"/> under the mouse cursor</param>
|
||||
private void Mouse_ColorChanged(object sender, System.Drawing.Color color)
|
||||
{
|
||||
ColorBrush = new SolidColorBrush(Color.FromArgb(color.A, color.R, color.G, color.B));
|
||||
ColorText = ColorRepresentationHelper.GetStringRepresentation(color, _userSettings.CopiedColorRepresentation.Value);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tell the color picker that the user have press a mouse button (after release the button)
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender of this event</param>
|
||||
/// <param name="p">The current <see cref="System.Drawing.Point"/> of the mouse cursor</param>
|
||||
private void MouseInfoProvider_OnMouseDown(object sender, System.Drawing.Point p)
|
||||
{
|
||||
string colorRepresentationToCopy = string.Empty;
|
||||
|
||||
switch (_userSettings.CopiedColorRepresentation.Value)
|
||||
{
|
||||
case ColorRepresentationType.HEX:
|
||||
colorRepresentationToCopy = HexColor;
|
||||
break;
|
||||
case ColorRepresentationType.RGB:
|
||||
colorRepresentationToCopy = RgbColor;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
CopyToClipboard(colorRepresentationToCopy);
|
||||
CopyToClipboard(ColorText);
|
||||
|
||||
_appStateHandler.HideColorPicker();
|
||||
PowerToysTelemetry.Log.WriteEvent(new ColorPickerShowEvent());
|
||||
}
|
||||
|
||||
private static void CopyToClipboard(string colorRepresentationToCopy)
|
||||
/// <summary>
|
||||
/// Copy the given text to the Windows clipboard
|
||||
/// </summary>
|
||||
/// <param name="text">The text to copy to the Windows clipboard</param>
|
||||
private static void CopyToClipboard(string text)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(colorRepresentationToCopy))
|
||||
if (string.IsNullOrEmpty(text))
|
||||
{
|
||||
// nasty hack - sometimes clipboard can be in use and it will raise and exception
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
Clipboard.SetText(colorRepresentationToCopy);
|
||||
break;
|
||||
}
|
||||
catch (COMException ex)
|
||||
{
|
||||
const uint CLIPBRD_E_CANT_OPEN = 0x800401D0;
|
||||
if ((uint)ex.ErrorCode != CLIPBRD_E_CANT_OPEN)
|
||||
{
|
||||
Logger.LogError("Failed to set text into clipboard", ex);
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
System.Threading.Thread.Sleep(10);
|
||||
// nasty hack - sometimes clipboard can be in use and it will raise and exception
|
||||
for (var i = 0; i < 10; i++)
|
||||
{
|
||||
try
|
||||
{
|
||||
Clipboard.SetText(text);
|
||||
break;
|
||||
}
|
||||
catch (COMException ex)
|
||||
{
|
||||
if ((uint)ex.ErrorCode != ErrorCodeClipboardCantOpen)
|
||||
{
|
||||
Logger.LogError("Failed to set text into clipboard", ex);
|
||||
}
|
||||
}
|
||||
|
||||
Thread.Sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Tell the color picker that the user have used the mouse wheel
|
||||
/// </summary>
|
||||
/// <param name="sender">The sender of this event</param>
|
||||
/// <param name="e">The new values for the zoom</param>
|
||||
private void MouseInfoProvider_OnMouseWheel(object sender, Tuple<Point, bool> e)
|
||||
{
|
||||
_zoomWindowHelper.Zoom(e.Item1, e.Item2);
|
||||
}
|
||||
|
||||
private static string ColorToHex(System.Drawing.Color c)
|
||||
{
|
||||
return "#" + c.R.ToString("X2", CultureInfo.InvariantCulture) + c.G.ToString("X2", CultureInfo.InvariantCulture) + c.B.ToString("X2", CultureInfo.InvariantCulture);
|
||||
}
|
||||
|
||||
private static string ColorToRGB(System.Drawing.Color c)
|
||||
{
|
||||
return "RGB(" + c.R.ToString(CultureInfo.InvariantCulture) + "," + c.G.ToString(CultureInfo.InvariantCulture) + "," + c.B.ToString(CultureInfo.InvariantCulture) + ")";
|
||||
}
|
||||
=> _zoomWindowHelper.Zoom(e.Item1, e.Item2);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,31 +1,55 @@
|
||||
<UserControl x:Class="ColorPicker.Views.MainView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:ColorPicker.Views"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:viewModel="clr-namespace:ColorPicker.ViewModels"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="50" d:DesignWidth="180"
|
||||
d:DataContext="{d:DesignInstance viewModel:MainViewModel, IsDesignTimeCreatable=True}">
|
||||
xmlns:constants="clr-namespace:ColorPicker.Constants"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="50"
|
||||
d:DesignWidth="{x:Static constants:WindowConstant.PickerWindowWidth}"
|
||||
d:DataContext="{d:DesignInstance viewModel:MainViewModel, IsDesignTimeCreatable=True}" >
|
||||
|
||||
<Grid Background="Transparent" >
|
||||
<Grid>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="20"/>
|
||||
<ColumnDefinition Width="50"/>
|
||||
<ColumnDefinition Width="20" />
|
||||
<ColumnDefinition Width="50" />
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition/>
|
||||
<RowDefinition/>
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Border BorderBrush="#505050" Grid.Column="2" Margin="0,1,1,1" Grid.RowSpan="2" BorderThickness="3,0,3,0" Background="#202020" CornerRadius="0" />
|
||||
<Border Background="{Binding ColorBrush}" BorderBrush="Black" Grid.Column="1" BorderThickness="1" Grid.RowSpan="2" x:Name="ColorBorder" CornerRadius="2,0,0,2"/>
|
||||
<Border Grid.RowSpan="2" Grid.ColumnSpan="2" Grid.Column="1" Background="Transparent" BorderThickness="1" BorderBrush="Black" CornerRadius="2"/>
|
||||
|
||||
<TextBlock Margin="7,5,5,5" Foreground="White" Grid.Row="0" Grid.Column="2" Text="{Binding HexColor}"/>
|
||||
<TextBlock Margin="7,0,0,0" Foreground="White" Grid.Row="1" Grid.Column="2" Text="{Binding RgbColor}"/>
|
||||
<Border Grid.Column="2"
|
||||
Margin="0,1,1,1"
|
||||
Background="#202020"
|
||||
BorderBrush="#505050"
|
||||
BorderThickness="3,0,3,0"
|
||||
CornerRadius="0" />
|
||||
|
||||
<Border Grid.Column="1"
|
||||
Background="{Binding ColorBrush}"
|
||||
BorderBrush="Black"
|
||||
BorderThickness="1"
|
||||
CornerRadius="2,0,0,2" />
|
||||
|
||||
<Border Grid.Column="1"
|
||||
Grid.ColumnSpan="2"
|
||||
Background="Transparent"
|
||||
BorderThickness="1"
|
||||
BorderBrush="Black"
|
||||
CornerRadius="2" />
|
||||
|
||||
<TextBlock Grid.Column="2"
|
||||
VerticalAlignment="Center"
|
||||
Margin="7,0,0,0"
|
||||
Foreground="White"
|
||||
Text="{Binding ColorText}" />
|
||||
|
||||
</Grid>
|
||||
</Grid>
|
||||
|
||||
</UserControl>
|
||||
|
||||
@@ -12,8 +12,6 @@ namespace ColorPicker.Views
|
||||
public partial class MainView : UserControl
|
||||
{
|
||||
public MainView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
=> InitializeComponent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +1,39 @@
|
||||
<UserControl x:Class="ColorPicker.Views.ZoomView"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:local="clr-namespace:ColorPicker.Views"
|
||||
mc:Ignorable="d"
|
||||
xmlns:shaders="clr-namespace:ColorPicker.Shaders"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:e="http://schemas.microsoft.com/expression/2010/interactivity"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:behaviors="clr-namespace:ColorPicker.Behaviors"
|
||||
d:DesignHeight="450" d:DesignWidth="800" Background="Transparent" Focusable="False">
|
||||
<Border BorderBrush="#FF2B2B2B" ClipToBounds="True" BorderThickness="2" CornerRadius="2">
|
||||
<Image Source="{Binding ZoomArea}" RenderOptions.BitmapScalingMode="NearestNeighbor" Stretch="Fill" Width="{Binding Width, Mode=TwoWay}" Height="{Binding Height, Mode=TwoWay}">
|
||||
xmlns:shaders="clr-namespace:ColorPicker.Shaders"
|
||||
Background="Transparent"
|
||||
Focusable="False"
|
||||
d:DesignHeight="450"
|
||||
d:DesignWidth="800"
|
||||
mc:Ignorable="d" >
|
||||
|
||||
<Border BorderBrush="#FF2B2B2B"
|
||||
BorderThickness="2"
|
||||
ClipToBounds="True"
|
||||
CornerRadius="2" >
|
||||
|
||||
<Image Source="{Binding ZoomArea}"
|
||||
Height="{Binding Height, Mode=TwoWay}"
|
||||
Width="{Binding Width, Mode=TwoWay}"
|
||||
RenderOptions.BitmapScalingMode="NearestNeighbor"
|
||||
Stretch="Fill" >
|
||||
|
||||
<e:Interaction.Behaviors>
|
||||
<behaviors:ResizeBehavior Width="{Binding DesiredWidth}" Height="{Binding DesiredHeight}"/>
|
||||
<behaviors:GridEffectBehavior Effect="{Binding ElementName=gridEffect}" ZoomFactor="{Binding ZoomFactor}"/>
|
||||
<behaviors:ResizeBehavior Width="{Binding DesiredWidth}" Height="{Binding DesiredHeight}" />
|
||||
<behaviors:GridEffectBehavior Effect="{Binding ElementName=gridEffect}" ZoomFactor="{Binding ZoomFactor}" />
|
||||
</e:Interaction.Behaviors>
|
||||
|
||||
<Image.Effect>
|
||||
<shaders:GridShaderEffect x:Name="gridEffect"/>
|
||||
<shaders:GridShaderEffect x:Name="gridEffect" />
|
||||
</Image.Effect>
|
||||
|
||||
</Image>
|
||||
|
||||
</Border>
|
||||
|
||||
</UserControl>
|
||||
|
||||
@@ -12,8 +12,6 @@ namespace ColorPicker.Views
|
||||
public partial class ZoomView : UserControl
|
||||
{
|
||||
public ZoomView()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
=> InitializeComponent();
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user