diff options
5 files changed, 194 insertions, 181 deletions
diff --git a/Xamarin.PropertyEditing.Tests/CommonColorTests.cs b/Xamarin.PropertyEditing.Tests/CommonColorTests.cs index f9f579f..3038f7d 100644 --- a/Xamarin.PropertyEditing.Tests/CommonColorTests.cs +++ b/Xamarin.PropertyEditing.Tests/CommonColorTests.cs @@ -9,30 +9,32 @@ namespace Xamarin.PropertyEditing.Tests public class CommonColorTests { public static readonly Dictionary<string, ColorTestCase> PrimaryTestCases = new Dictionary<string, ColorTestCase> { - // { name, r g b c% m% y% k% h° l% s% b% a} - { "Black", new ColorTestCase( 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0) }, - { "White", new ColorTestCase(255, 255, 255, 0, 0, 0, 0, 0, 100, 0, 100) }, - { "Gray", new ColorTestCase(127, 127, 127, 0, 0, 0, 50, 0, 50, 0, 50) }, - { "Silver", new ColorTestCase(191, 191, 191, 0, 0, 0, 25, 0, 75, 0, 75) }, - { "Red", new ColorTestCase(255, 0, 0, 0, 100, 100, 0, 0, 50, 100, 100) }, - { "Lime", new ColorTestCase( 0, 255, 0, 100, 0, 100, 0, 120, 50, 100, 100) }, - { "Blue", new ColorTestCase( 0, 0, 255, 100, 100, 0, 0, 240, 50, 100, 100) }, - { "Yellow", new ColorTestCase(255, 255, 0, 0, 0, 100, 0, 60, 50, 100, 100) }, - { "Cyan", new ColorTestCase( 0, 255, 255, 100, 0, 0, 0, 180, 50, 100, 100) }, - { "Magenta", new ColorTestCase(255, 0, 255, 0, 100, 0, 0, 300, 50, 100, 100) }, - { "Maroon", new ColorTestCase(127, 0, 0, 0, 100, 100, 50, 0, 25, 100, 50) }, - { "Green", new ColorTestCase( 0, 127, 0, 100, 0, 100, 50, 120, 25, 100, 50) }, - { "Navy", new ColorTestCase( 0, 0, 127, 100, 100, 0, 50, 240, 25, 100, 50) }, - { "Olive", new ColorTestCase(127, 127, 0, 0, 0, 100, 50, 60, 25, 100, 50) }, - { "Purple", new ColorTestCase(127, 0, 127, 0, 100, 0, 50, 300, 25, 100, 50) }, - { "Teal", new ColorTestCase( 0, 127, 127, 100, 0, 0, 50, 180, 25, 100, 50) }, + // { name, r g b c% m% y% k% h° l% s% b% } + { "Black", new ColorTestCase( 0, 0, 0, 0, 0, 0, 100, 0, 0, 0, 0) }, + { "White", new ColorTestCase(255, 255, 255, 0, 0, 0, 0, 0, 100, 0, 100) }, + { "Gray", new ColorTestCase(128, 128, 128, 0, 0, 0, 50, 0, 50, 0, 50) }, + { "Silver", new ColorTestCase(191, 191, 191, 0, 0, 0, 25, 0, 74.9, 0, 74.9) }, + { "Red", new ColorTestCase(255, 0, 0, 0, 100, 100, 0, 0, 50, 100, 100) }, + { "Lime", new ColorTestCase( 0, 255, 0, 100, 0, 100, 0, 120, 50, 100, 100) }, + { "Blue", new ColorTestCase( 0, 0, 255, 100, 100, 0, 0, 240, 50, 100, 100) }, + { "Yellow", new ColorTestCase(255, 255, 0, 0, 0, 100, 0, 60, 50, 100, 100) }, + { "Cyan", new ColorTestCase( 0, 255, 255, 100, 0, 0, 0, 180, 50, 100, 100) }, + { "Magenta", new ColorTestCase(255, 0, 255, 0, 100, 0, 0, 300, 50, 100, 100) }, + { "Maroon", new ColorTestCase(128, 0, 0, 0, 100, 100, 50, 0, 25.1, 100, 50) }, + { "Green", new ColorTestCase( 0, 128, 0, 100, 0, 100, 50, 120, 25.1, 100, 50) }, + { "Navy", new ColorTestCase( 0, 0, 128, 100, 100, 0, 50, 240, 25.1, 100, 50) }, + { "Olive", new ColorTestCase(128, 128, 0, 0, 0, 100, 50, 60, 25.1, 100, 50) }, + { "Purple", new ColorTestCase(128, 0, 128, 0, 100, 0, 50, 300, 25.1, 100, 50) }, + { "Teal", new ColorTestCase( 0, 128, 128, 100, 0, 0, 50, 180, 25.1, 100, 50) }, }; public static readonly Dictionary<string, ColorTestCase> RGBTestCases = new Dictionary<string, ColorTestCase> { - // { name, r g b c% m% y% k% h° l% s% b% a} - { "Orange", new ColorTestCase(255, 164, 0, 0, 35.7, 100, 0, 38.6, 50, 100, 100) }, - { "MediumSpringGreen", new ColorTestCase( 0, 250, 154, 100, 0, 38, 2, 157, 49, 100, 98) }, - { "Chocolate", new ColorTestCase(209, 117, 52, 0, 44, 75.1, 18, 24.8, 47, 75.1, 82) }, + // { name, r g b c% m% y% k% h° l% s% b% } + { "Orange", new ColorTestCase(255, 164, 0, 0, 35.7, 100, 0, 38.6, 50, 100, 100) }, + { "MediumSpringGreen", new ColorTestCase( 0, 250, 155, 100, 0, 38, 2, 157.2, 49, 100, 98) }, + { "Chocolate", new ColorTestCase(209, 117, 52, 0, 44, 75.1, 18, 24.8, 51, 75.1, 82) }, + { "MoreOrange", new ColorTestCase(200, 101, 31, 0, 49.5, 84.5, 21.6, 24.9, 45.3, 84.5, 78.4) }, + { "Lilac", new ColorTestCase(101, 31, 255, 60.4, 87.8, 0, 0, 258.8, 56.1, 87.8, 100) }, }; [Test, TestCaseSource (typeof(CommonColorTests), "HueColorFromColorCases")] @@ -71,6 +73,9 @@ namespace Xamarin.PropertyEditing.Tests foreach (KeyValuePair<string, ColorTestCase> testCaseKVP in PrimaryTestCases) { yield return new TestCaseData (testCaseKVP.Value.CMYK).Returns (testCaseKVP.Value.Color).SetName ("ColorFromCMYK_" + testCaseKVP.Key); } + foreach (KeyValuePair<string, ColorTestCase> testCaseKVP in RGBTestCases) { + yield return new TestCaseData (testCaseKVP.Value.CMYK).Returns (testCaseKVP.Value.Color).SetName ("ColorFromCMYK_" + testCaseKVP.Key); + } } [Test, TestCaseSource (typeof (CommonColorTests), "HLSFromColorCases")] @@ -94,6 +99,10 @@ namespace Xamarin.PropertyEditing.Tests foreach (KeyValuePair<string, ColorTestCase> testCaseKVP in PrimaryTestCases) { yield return new TestCaseData (testCaseKVP.Value.HLS).Returns (testCaseKVP.Value.Color).SetName ("ColorFromHLS_" + testCaseKVP.Key); } + // HLS -> RGB conversion is the least reliable, and round-tripping it doesn't quite guarantee accurate enough results that they can be tested for arbitrary colors. + //foreach (KeyValuePair<string, ColorTestCase> testCaseKVP in RGBTestCases) { + // yield return new TestCaseData (testCaseKVP.Value.HLS).Returns (testCaseKVP.Value.Color).SetName ("ColorFromHLS_" + testCaseKVP.Key); + //} } [Test, TestCaseSource (typeof (CommonColorTests), "HLSRoundTripCases")] @@ -108,6 +117,9 @@ namespace Xamarin.PropertyEditing.Tests foreach (KeyValuePair<string, ColorTestCase> testCaseKVP in PrimaryTestCases) { yield return new TestCaseData (testCaseKVP.Value.HLS).Returns (testCaseKVP.Value.HLS).SetName ("HLSRoundTrip_" + testCaseKVP.Key); } + foreach (KeyValuePair<string, ColorTestCase> testCaseKVP in RGBTestCases) { + yield return new TestCaseData (testCaseKVP.Value.HLS).Returns (testCaseKVP.Value.HLS).SetName ("HLSRoundTrip_" + testCaseKVP.Key); + } } [Test, TestCaseSource (typeof (CommonColorTests), "HSBFromColorCases")] @@ -131,6 +143,9 @@ namespace Xamarin.PropertyEditing.Tests foreach (KeyValuePair<string, ColorTestCase> testCaseKVP in PrimaryTestCases) { yield return new TestCaseData (testCaseKVP.Value.HSB).Returns (testCaseKVP.Value.Color).SetName ("ColorFromHSB_" + testCaseKVP.Key); } + foreach (KeyValuePair<string, ColorTestCase> testCaseKVP in RGBTestCases) { + yield return new TestCaseData (testCaseKVP.Value.HSB).Returns (testCaseKVP.Value.Color).SetName ("ColorFromHSB_" + testCaseKVP.Key); + } } [Test, TestCaseSource (typeof (CommonColorTests), "HSBRoundTripCases")] @@ -145,6 +160,9 @@ namespace Xamarin.PropertyEditing.Tests foreach (KeyValuePair<string, ColorTestCase> testCaseKVP in PrimaryTestCases) { yield return new TestCaseData (testCaseKVP.Value.HSB).Returns (testCaseKVP.Value.HSB).SetName ("HSBRoundTrip_" + testCaseKVP.Key); } + foreach (KeyValuePair<string, ColorTestCase> testCaseKVP in RGBTestCases) { + yield return new TestCaseData (testCaseKVP.Value.HSB).Returns (testCaseKVP.Value.HSB).SetName ("HSBRoundTrip_" + testCaseKVP.Key); + } } [Test] @@ -189,10 +207,10 @@ namespace Xamarin.PropertyEditing.Tests public override bool Equals (object obj) { var other = (CMYK)obj; - return Math.Round (other.C - C, 2) == 0 - && Math.Round (other.M - M, 2) == 0 - && Math.Round (other.Y - Y, 2) == 0 - && Math.Round (other.K - K, 2) == 0; + return Math.Round (other.C, 2) == Math.Round(C, 2) + && Math.Round (other.M, 2) == Math.Round (M, 2) + && Math.Round (other.Y, 2) == Math.Round (Y, 2) + && Math.Round (other.K, 2) == Math.Round (K, 2); } public override string ToString () => $"{{ C:{C:P1}, M:{M:P1}, Y:{Y:P1}, K:{K:P1} }}"; @@ -214,9 +232,9 @@ namespace Xamarin.PropertyEditing.Tests public override bool Equals (object obj) { var other = (HLS)obj; - return Math.Round (other.Hue - Hue, 1) == 0 - && Math.Round (other.Lightness - Lightness, 1) == 0 - && Math.Round (other.Saturation - Saturation, 1) == 0; + return Math.Round (other.Hue, 1) == Math.Round(Hue, 1) + && Math.Round (other.Lightness, 1) == Math.Round(Lightness, 1) + && Math.Round (other.Saturation, 1) == Math.Round(Saturation, 1); } public override string ToString () => $"{{ H:{Hue:F1}°, S:{Saturation:P1}, L:{Lightness:P1} }}"; @@ -238,9 +256,9 @@ namespace Xamarin.PropertyEditing.Tests public override bool Equals (object obj) { var other = (HSB)obj; - return Math.Round (other.Hue - Hue, 1) == 0 - && Math.Round (other.Saturation - Saturation, 1) == 0 - && Math.Round (other.Brightness - Brightness, 1) == 0; + return Math.Round (other.Hue, 1) == Math.Round(Hue, 1) + && Math.Round (other.Saturation, 1) == Math.Round(Saturation, 1) + && Math.Round (other.Brightness, 1) == Math.Round(Brightness, 1); } public override string ToString () => $"{{ H:{Hue:F1}°, S:{Saturation:P1}, B:{Brightness:P1} }}"; diff --git a/Xamarin.PropertyEditing.Windows/EditorPropertySelector.cs b/Xamarin.PropertyEditing.Windows/EditorPropertySelector.cs index 22118c3..9cddbe8 100644 --- a/Xamarin.PropertyEditing.Windows/EditorPropertySelector.cs +++ b/Xamarin.PropertyEditing.Windows/EditorPropertySelector.cs @@ -47,8 +47,6 @@ namespace Xamarin.PropertyEditing.Windows return base.TryGetTemplateType (type, out templateType); } - private static readonly EditorPropertySelector selector; - private static readonly Dictionary<Type, Type> TypeMap = new Dictionary<Type, Type> { { typeof(BrushPropertyViewModel), typeof(BrushTabbedEditorControl) } }; diff --git a/Xamarin.PropertyEditing.Windows/ResourceBrushEditorControl.cs b/Xamarin.PropertyEditing.Windows/ResourceBrushEditorControl.cs index 53876b6..6d3a3ca 100644 --- a/Xamarin.PropertyEditing.Windows/ResourceBrushEditorControl.cs +++ b/Xamarin.PropertyEditing.Windows/ResourceBrushEditorControl.cs @@ -1,11 +1,5 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; -using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; -using Xamarin.PropertyEditing.Drawing; using Xamarin.PropertyEditing.ViewModels; namespace Xamarin.PropertyEditing.Windows @@ -17,8 +11,6 @@ namespace Xamarin.PropertyEditing.Windows DefaultStyleKeyProperty.OverrideMetadata (typeof (ResourceBrushEditorControl), new FrameworkPropertyMetadata (typeof (ResourceBrushEditorControl))); } - ListBox resourceList; - BrushPropertyViewModel ViewModel => DataContext as BrushPropertyViewModel; } } diff --git a/Xamarin.PropertyEditing/Drawing/CommonColor.cs b/Xamarin.PropertyEditing/Drawing/CommonColor.cs index 632b033..73e563a 100644 --- a/Xamarin.PropertyEditing/Drawing/CommonColor.cs +++ b/Xamarin.PropertyEditing/Drawing/CommonColor.cs @@ -9,87 +9,72 @@ namespace Xamarin.PropertyEditing.Drawing public struct CommonColor : IEquatable<CommonColor> { public CommonColor (byte r, byte g, byte b, byte a = 255, string label = null) + : this ((double)r, g, b, a, label) { } + private CommonColor (double r, double g, double b, byte a = 255, string label = null) { + this.r = r; + this.g = g; + this.b = b; A = a; - R = r; - G = g; - B = b; Label = label; - c = null; - m = null; - y = null; - k = null; - hueR = null; - hueG = 0; - hueB = 0; - hue = null; - lightness = null; - brightness = null; - saturation = null; + this.c = null; + this.m = null; + this.y = null; + this.k = null; + this.hueR = null; + this.hueG = 0; + this.hueB = 0; + this.hue = null; + this.lightness = null; + this.brightness = null; + this.saturation = null; } /// <summary> - /// Alpha channel - /// </summary> - public byte A { get; } - - /// <summary> /// Red component /// </summary> - public byte R { get; } + public byte R => DoubleToByte (this.r); /// <summary> /// Green component /// </summary> - public byte G { get; } + public byte G => DoubleToByte (this.g); /// <summary> /// Blue component /// </summary> - public byte B { get; } + public byte B => DoubleToByte (this.b); + + /// <summary> + /// Alpha channel + /// </summary> + public byte A { get; } /// <summary> /// An optional label for the color, that does not affect equality or anything else. /// </summary> public string Label { get; set; } - double? k; /// <summary> /// Black component /// </summary> - public double K => k ?? (k = (double)(255 - (R >= G ? (R >= B ? R : B) : (G >= B ? G : B))) / 255).Value; - - double Complement(byte component, double k) - { - if (k == 1) return 0; - var val = (1 - k - (double)component / 255) / (1 - k); - if (val < 0) return 0; - if (val > 1) return 1; - return val; - } - - double? c; + public double K => this.k ?? (this.k = + (255 - (this.r >= this.g ? (this.r >= this.b ? this.r : this.b) : (this.g >= this.b ? this.g : this.b))) / 255).Value; /// <summary> /// Cyan component /// </summary> - public double C => c ?? (c = Complement(R, K)).Value; + public double C => this.c ?? (this.c = Complement(this.r, K)).Value; - double? m; /// <summary> /// Magenta component /// </summary> - public double M => m ?? (m = Complement(G, K)).Value; + public double M => this.m ?? (this.m = Complement(this.g, K)).Value; - double? y; /// <summary> /// Yellow component /// </summary> - public double Y => y ?? (y = Complement(B, K)).Value; + public double Y => this.y ?? (this.y = Complement(this.b, K)).Value; - static readonly CommonColor Red = new CommonColor (255, 0, 0); - - byte? hueR; - byte hueG, hueB; /// <summary> /// Gets a hue from this color. /// A hue has the highest component of the passed-in color at 255, @@ -101,103 +86,103 @@ namespace Xamarin.PropertyEditing.Drawing /// </summary> public CommonColor HueColor { get { - if (hueR.HasValue) return new CommonColor(hueR.Value, hueG, hueB); + if (this.hueR.HasValue) + return new CommonColor(this.hueR.Value, this.hueG, this.hueB); // Map grey to red if (IsGrey) { - hueR = 255; - hueG = 0; - hueB = 0; - hue = 0; - return Red; + this.hueR = 255; + this.hueG = 0; + this.hueB = 0; + this.hue = 0; + return new CommonColor(255, 0, 0); } - var isRedMax = R >= G && R >= B; - var isGreenMax = G >= R && G >= B; - var isRedMin = R <= G && R <= B; - var isGreenMin = G <= R && G <= B; + var isRedMax = this.r >= this.g && this.r >= this.b; + var isGreenMax = this.g >= this.r && this.g >= this.b; + var isRedMin = this.r <= this.g && this.r <= this.b; + var isGreenMin = this.g <= this.r && this.g <= this.b; CommonColor hueColor = isRedMax ? // Red is max isGreenMin ? // Green is min - new CommonColor (255, 0, InterpolateComponent (B, G, R)) : + new CommonColor (255, 0, InterpolateComponent (this.b, this.g, this.r)) : // Blue is min - new CommonColor (255, InterpolateComponent (G, B, R), 0) : + new CommonColor (255, InterpolateComponent (this.g, this.b, this.r), 0) : isGreenMax ? // Green is max isRedMin ? // Red is min - new CommonColor (0, 255, InterpolateComponent (B, R, G)) : + new CommonColor (0, 255, InterpolateComponent (this.b, this.r, this.g)) : // Blue is min - new CommonColor (InterpolateComponent (R, B, G), 255, 0) : + new CommonColor (InterpolateComponent (this.r, this.b, this.g), 255, 0) : // Blue is max isRedMin ? // Red is min - new CommonColor (0, InterpolateComponent (G, R, B), 255) : + new CommonColor (0, InterpolateComponent (this.g, this.r, this.b), 255) : // Green is min - new CommonColor (InterpolateComponent (R, G, B), 0, 255); + new CommonColor (InterpolateComponent (this.r, this.g, this.b), 0, 255); - hueR = hueColor.R; - hueG = hueColor.G; - hueB = hueColor.B; + this.hueR = hueColor.r; + this.hueG = hueColor.g; + this.hueB = hueColor.b; return hueColor; } } - double? hue; /// <summary> /// The hue for this color, as an angle between 0 and 360 degrees. /// </summary> public double Hue { get { - if (hue.HasValue) return hue.Value; + if (this.hue.HasValue) return this.hue.Value; // Map grey to 0 degrees if (IsGrey) { - hueR = 255; - hueG = 0; - hueB = 0; - hue = 0; + this.hueR = 255; + this.hueG = 0; + this.hueB = 0; + this.hue = 0; return 0; } - var isRedMax = R >= G && R >= B; - var isGreenMax = G >= R && G >= B; - var isRedMin = R <= G && R <= B; - var isGreenMin = G <= R && G < B; - var d = ((double)(isRedMax ? R : isGreenMax ? G : B) - (isRedMin ? R : isGreenMin ? G : B)); + var isRedMax = this.r >= this.g && this.r >= this.b; + var isGreenMax = this.g >= this.r && this.g >= this.b; + var isRedMin = this.r <= this.g && this.r <= this.b; + var isGreenMin = this.g <= this.r && this.g <= this.b; + + var d = (isRedMax ? this.r : isGreenMax ? this.g : this.b) - (isRedMin ? this.r : isGreenMin ? this.g : this.b); - hue = - isRedMax ? (Mod((G - B) / d, 6)) * 60 : - isGreenMax ? (((B - R)/ d) + 2) * 60 : - (((R - G) / d) + 4) * 60; + this.hue = + isRedMax ? (Mod((this.g - this.b) / d, 6)) * 60 : + isGreenMax ? (((this.b - this.r)/ d) + 2) * 60 : + (((this.r - this.g) / d) + 4) * 60; - return hue.Value; + return this.hue.Value; } } - double? lightness; /// <summary> /// The lightness of the color, where white is 1, black is 0, and primary colors are 0.5. /// </summary> public double Lightness { get { - if (lightness.HasValue) return lightness.Value; + if (this.lightness.HasValue) return this.lightness.Value; - var isRedMax = R >= G && R >= B; - var isGreenMax = G >= R && G >= B; - var isRedMin = R <= G && R <= B; - var isGreenMin = G <= R && G <= B; + var isRedMax = this.r >= this.g && this.r >= this.b; + var isGreenMax = this.g >= this.r && this.g >= this.b; + var isRedMin = this.r <= this.g && this.r <= this.b; + var isGreenMin = this.g <= this.r && this.g <= this.b; - lightness = ((double)(isRedMax ? R : isGreenMax ? G : B) + (isRedMin ? R : isGreenMin ? G : B)) / 510; + this.lightness = + ((isRedMax ? this.r : isGreenMax ? this.g : this.b) + (isRedMin ? this.r : isGreenMin ? this.g : this.b)) / 510; - return lightness.Value; + return this.lightness.Value; } } - double? brightness; /// <summary> /// A brightness between 0 and 1, 1 being the measure for the hue of the color /// (the hue being a fully-saturated version of the same color), and 0 being @@ -205,20 +190,19 @@ namespace Xamarin.PropertyEditing.Drawing /// </summary> public double Brightness { get { - if (brightness.HasValue) return brightness.Value; + if (this.brightness.HasValue) return this.brightness.Value; CommonColor hue = HueColor; var isRedMaxed = hue.R == 255; var isGreenMaxed = hue.G == 255; - return (brightness = - isRedMaxed ? (double)R / 255 : - isGreenMaxed ? (double)G / 255 : - (double)B / 255 + return (this.brightness = + isRedMaxed ? this.r / 255 : + isGreenMaxed ? this.g / 255 : + this.b / 255 ).Value; } } - double? saturation; /// <summary> /// A saturation between 0 and 1, 1 being the measure for the hue of the color /// (the hue being a fully saturated version of the color), and 0 being the @@ -226,27 +210,48 @@ namespace Xamarin.PropertyEditing.Drawing /// </summary> public double Saturation { get { - if (saturation.HasValue) return saturation.Value; + if (this.saturation.HasValue) return this.saturation.Value; - if (IsGrey) return (saturation = 0).Value; + if (IsGrey) return (this.saturation = 0).Value; - var isRedMax = R >= G && R >= B; - var isGreenMax = G >= R && G >= B; - var isRedMin = R <= G && R <= B; - var isGreenMin = G <= R && G <= B; + var isRedMax = this.r >= this.g && this.r >= this.b; + var isGreenMax = this.g >= this.r && this.g >= this.b; + var isRedMin = this.r <= this.g && this.r <= this.b; + var isGreenMin = this.g <= this.r && this.g <= this.b; - var max = (double)(isRedMax ? R : isGreenMax ? G : B); - var d = (max - (isRedMin ? R : isGreenMin ? G : B)); + var max = isRedMax ? this.r : isGreenMax ? this.g : this.b; + var d = (max - (isRedMin ? this.r : isGreenMin ? this.g : this.b)); - saturation = d / max; + this.saturation = d / max; - return saturation.Value; + return this.saturation.Value; } } - static readonly int[][] redRanges = new[] { new[] { 0, 60 }, new[] { 300, 360 } }; - static readonly int[][] greenRanges = new[] { new[] { 60, 180 } }; - static readonly int[][] blueRanges = new[] { new[] { 180, 300 } }; + private readonly double r; + private readonly double g; + private readonly double b; + private double? k; + private double? c; + private double? m; + private double? y; + private double? hue; + private double? hueR; + private double hueG, hueB; + private double? lightness; + private double? brightness; + private double? saturation; + + private double Complement (double component, double k) + { + if (k == 1) return 0; + var val = (1 - k - component / 255) / (1 - k); + return val < 0 ? 0 : val > 1 ? 1 : val; + } + + private static readonly int[][] redRanges = new[] { new[] { 0, 60 }, new[] { 300, 360 } }; + private static readonly int[][] greenRanges = new[] { new[] { 60, 180 } }; + private static readonly int[][] blueRanges = new[] { new[] { 180, 300 } }; /// <summary> /// Finds the hue color from a hue angle between 0 and 360 degrees. @@ -281,20 +286,20 @@ namespace Xamarin.PropertyEditing.Drawing /// <param name="hue">The hue, between 0 and 360</param> /// <param name="intervals">A set of intervals where the component is 255.</param> /// <returns>The value of the component.</returns> - static byte GetHueComponent (double hue, int[][] intervals) + private static double GetHueComponent (double hue, int[][] intervals) { if (hue < 0 || hue > 360) throw new ArgumentOutOfRangeException (nameof (hue), "Position must be between 0 and 6."); - foreach (int[] interval in intervals) { + foreach (var interval in intervals) { // Component is 255 inside the interval if (hue >= interval[0] && hue <= interval[1]) return 255; // Component linearly grows from 0 to 255 60 degrees left of the interval if (hue >= interval[0] - 60 && hue < interval[0]) - return (byte)((hue - interval[0] + 60) * 255 / 60); + return (hue - interval[0] + 60) * 255 / 60; // Component linearly falls from 255 to 0 60 degrees right of the interval if (hue > interval[1] && hue <= interval[1] + 60) - return (byte)(255 - (hue - interval[1]) * 255 / 60); + return 255 - (hue - interval[1]) * 255 / 60; } // Otherwise, it's zero return 0; @@ -311,27 +316,27 @@ namespace Xamarin.PropertyEditing.Drawing // We're between 0 and 120 if (hueColor.R == 255) { // We're between 0 and 60, and green is on the rising phase - return (double)hueColor.G * 60 / 255; + return hueColor.g * 60 / 255; } // We're between 60 and 120, and red is on the declining phase - return ((double)(255 - hueColor.R) * 60 / 255 + 60); + return ((255 - hueColor.r) * 60 / 255 + 60); } else if (hueColor.R == 0) { // We're between 120 and 240 if (hueColor.G == 255) { // We're between 120 and 180, and blue is on the rise - return ((double)hueColor.B * 60 / 255 + 120); + return (hueColor.b * 60 / 255 + 120); } // We're between 180 and 240, and green is declining - return ((double)(255 - hueColor.G) * 60 / 255 + 180); + return ((255 - hueColor.g) * 60 / 255 + 180); } // We're between 240 and 360 if (hueColor.B == 255) { // We're between 240 and 300, and red is on the rise - return ((double)hueColor.R * 60 / 255 + 240); + return (hueColor.r * 60 / 255 + 240); } // We're between 300 and 360, and blue is declining - return ((double)(255 - hueColor.B) * 60 / 255 + 300); + return ((255 - hueColor.b) * 60 / 255 + 300); } /// <summary> @@ -347,11 +352,10 @@ namespace Xamarin.PropertyEditing.Drawing /// <param name="lowest">The lowest component value</param> /// <param name="highest">The highest component value</param> /// <returns>The interpolated third component</returns> - static byte InterpolateComponent (byte component, byte lowest, byte highest) + static double InterpolateComponent (double component, double lowest, double highest) { var delta = highest - lowest; - if (delta == 0) return highest; - return (byte)((component - lowest) * 255 / delta); + return delta == 0 ? highest : (component - lowest) * 255 / delta; } /// <summary> @@ -378,9 +382,9 @@ namespace Xamarin.PropertyEditing.Drawing throw new ArgumentOutOfRangeException (nameof (k)); } var color = new CommonColor ( - (byte)(255 * (1 - c) * (1 - k)), - (byte)(255 * (1 - m) * (1 - k)), - (byte)(255 * (1 - y) * (1 - k)), + 255 * (1 - c) * (1 - k), + 255 * (1 - m) * (1 - k), + 255 * (1 - y) * (1 - k), alpha) { // pre-cache CMYK components, since we know them, and it will improve round-tripping c = c, @@ -428,7 +432,7 @@ namespace Xamarin.PropertyEditing.Drawing hue < 180 || hue >= 300 ? x : c; - var color = new CommonColor ((byte)(255 * (r + m)), (byte)(255 * (g + m)), (byte)(255 * (b + m)), alpha) { + var color = new CommonColor (255 * (r + m), 255 * (g + m), 255 * (b + m), alpha) { // Pre-cache HLS components, since we know them, and it will improve round-tripping hue = hue, lightness = lightness, @@ -474,7 +478,7 @@ namespace Xamarin.PropertyEditing.Drawing hue < 180 || hue >= 300 ? x : c; - var color = new CommonColor ((byte)(255 * (r + m)), (byte)(255 * (g + m)), (byte)(255 * (b + m)), alpha) { + var color = new CommonColor (255 * (r + m), 255 * (g + m), 255 * (b + m), alpha) { // Pre-cache HLS components, since we know them, and it will improve round-tripping hue = hue, brightness = brightness, @@ -488,13 +492,16 @@ namespace Xamarin.PropertyEditing.Drawing private static double Mod (double a, double b) => a - b * Math.Floor (a / b); - public override bool Equals (object obj) + private static byte DoubleToByte(double? d) { - if (obj == null) return false; - if (!(obj is CommonColor otherColor)) return false; - return Equals (otherColor, false); + if (!d.HasValue) return 0; + var round = Math.Round (d.Value); + return (byte)(round < 0 ? 0 : round > 255 ? 255 : round); } + public override bool Equals (object obj) + => obj == null ? false : !(obj is CommonColor otherColor) ? false : Equals (otherColor, false); + public bool Equals (CommonColor other) => Equals (other, false); public bool Equals (CommonColor other, bool ignoreAlpha) @@ -509,9 +516,9 @@ namespace Xamarin.PropertyEditing.Drawing public static bool operator != (CommonColor left, CommonColor right) => !Equals (left, right); public static double SquaredDistance (CommonColor left, CommonColor right) - => (left.R - right.R) * (left.R - right.R) - + (left.G - right.G) * (left.G - right.G) - + (left.B - right.B) * (left.B - right.B); + => (left.r - right.r) * (left.r - right.r) + + (left.g - right.g) * (left.g - right.g) + + (left.b - right.b) * (left.b - right.b); public override int GetHashCode () { diff --git a/Xamarin.PropertyEditing/ViewModels/MaterialDesignColorViewModel.cs b/Xamarin.PropertyEditing/ViewModels/MaterialDesignColorViewModel.cs index 1c0453f..c88c328 100644 --- a/Xamarin.PropertyEditing/ViewModels/MaterialDesignColorViewModel.cs +++ b/Xamarin.PropertyEditing/ViewModels/MaterialDesignColorViewModel.cs @@ -41,11 +41,9 @@ namespace Xamarin.PropertyEditing.ViewModels { get { // Debug.WriteLine ($"Getting ColorName ({this.colorName})"); - if (this.colorName != null) return this.colorName; - if (Parent.Value is CommonSolidBrush solidBrush) { - return (this.colorName = Palette.Name); - } - return (this.colorName = Strings.MaterialColorGrey); + return this.colorName ?? + (Parent.Value is CommonSolidBrush solidBrush ? (this.colorName = Palette.Name) + : (this.colorName = Strings.MaterialColorGrey)); } set { // Debug.WriteLine ($"Setting ColorName to {value}"); @@ -251,9 +249,9 @@ namespace Xamarin.PropertyEditing.ViewModels Color = new CommonColor (newColor.R, newColor.G, newColor.B, alpha); } - private static string[] NormalNames = new[] { "50", "100", "200", "300", "400", "500", "600", "700", "800", "900" }; - private static string[] AccentNames = new[] { "A100", "A200", "A400", "A700" }; - private static string[] BlackAndWhiteNames = new[] { Strings.White, Strings.Black }; + private static readonly string[] NormalNames = new[] { "50", "100", "200", "300", "400", "500", "600", "700", "800", "900" }; + private static readonly string[] AccentNames = new[] { "A100", "A200", "A400", "A700" }; + private static readonly string[] BlackAndWhiteNames = new[] { Strings.White, Strings.Black }; private static MaterialColorScale FindPalette (string colorName, bool isAccent = false) { |