This commit is contained in:
Wiesław Šoltés 2018-11-03 13:13:02 +01:00
Родитель f266ff12df
Коммит 6523bef8e3
11 изменённых файлов: 320 добавлений и 160 удалений

Просмотреть файл

@ -41,8 +41,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "props", "props", "{A88815F2
build\Newtonsoft.Json.props = build\Newtonsoft.Json.props
build\ReactiveUI.props = build\ReactiveUI.props
build\Rx.props = build\Rx.props
build\XUnit.props = build\XUnit.props
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "tests", "tests", "{F2D7C825-1AC1-45FF-A221-CEE80E2F2374}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThemeEditor.Colors", "src\ThemeEditor.Colors\ThemeEditor.Colors.csproj", "{BFDD803E-2B9B-46A2-AC25-C77FD2376893}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ThemeEditor.Colors.UnitTests", "tests\ThemeEditor.Colors.UnitTests\ThemeEditor.Colors.UnitTests.csproj", "{E2079787-7F2F-46F8-BD56-2C226D883904}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -57,6 +64,14 @@ Global
{2B5611EB-1E0D-4EAB-96C9-821A965E496B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2B5611EB-1E0D-4EAB-96C9-821A965E496B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2B5611EB-1E0D-4EAB-96C9-821A965E496B}.Release|Any CPU.Build.0 = Release|Any CPU
{BFDD803E-2B9B-46A2-AC25-C77FD2376893}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{BFDD803E-2B9B-46A2-AC25-C77FD2376893}.Debug|Any CPU.Build.0 = Debug|Any CPU
{BFDD803E-2B9B-46A2-AC25-C77FD2376893}.Release|Any CPU.ActiveCfg = Release|Any CPU
{BFDD803E-2B9B-46A2-AC25-C77FD2376893}.Release|Any CPU.Build.0 = Release|Any CPU
{E2079787-7F2F-46F8-BD56-2C226D883904}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E2079787-7F2F-46F8-BD56-2C226D883904}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E2079787-7F2F-46F8-BD56-2C226D883904}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E2079787-7F2F-46F8-BD56-2C226D883904}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -68,6 +83,8 @@ Global
{497FBEFD-7228-4E2F-A947-9F416498E263} = {3353FD4A-FE9B-4670-86C9-09EF0F7CEDB2}
{9A80222C-EDE8-42AF-9D6D-76325FC4673F} = {3353FD4A-FE9B-4670-86C9-09EF0F7CEDB2}
{A88815F2-21C3-4EBA-8DBC-0A461EA7F82C} = {3353FD4A-FE9B-4670-86C9-09EF0F7CEDB2}
{BFDD803E-2B9B-46A2-AC25-C77FD2376893} = {219954C4-6A40-4D94-914E-148B7EBB718E}
{E2079787-7F2F-46F8-BD56-2C226D883904} = {F2D7C825-1AC1-45FF-A221-CEE80E2F2374}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {CF676549-9409-4598-8229-80E04B51ADC5}

Просмотреть файл

@ -0,0 +1,98 @@
using System;
namespace ThemeEditor.Colors
{
public readonly struct HSV
{
public double H { get; }
public double S { get; }
public double V { get; }
public HSV(double h, double s, double v)
{
H = h;
S = s;
V = v;
}
public HSV(HSV hsv)
{
H = hsv.H;
S = hsv.S;
V = hsv.V;
}
public HSV(RGB rgb)
{
HSV hsv = rgb.ToHSV();
H = hsv.H;
S = hsv.S;
V = hsv.V;
}
public RGB ToRGB() => ToRGB(H, S, V);
public static RGB ToRGB(double h, double s, double v)
{
double R = default;
double G = default;
double B = default;
if (s == 0)
{
R = G = B = Math.Round(v * 2.55);
return new RGB(R, G, B);
}
s = s / 100;
v = v / 100;
h /= 60;
var i = Math.Floor(h);
var f = h - i;
var p = v * (1 - s);
var q = v * (1 - s * f);
var t = v * (1 - s * (1 - f));
switch ((int)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;
}
R = Math.Round(R * 255);
G = Math.Round(G * 255);
B = Math.Round(B * 255);
return new RGB(R, G, B);
}
}
}

Просмотреть файл

@ -0,0 +1,109 @@
using System;
namespace ThemeEditor.Colors
{
public readonly struct RGB
{
public double R { get; }
public double G { get; }
public double B { get; }
public RGB(double r, double g, double b)
{
R = r;
G = g;
B = b;
}
public RGB(RGB rgb)
{
R = rgb.R;
G = rgb.G;
B = rgb.B;
}
public RGB(HSV hsv)
{
RGB rgb = hsv.ToRGB();
R = rgb.R;
G = rgb.G;
B = rgb.B;
}
public HSV ToHSV() => ToHSV(R, G, B);
public static HSV ToHSV(double r, double g, double b)
{
double H = default;
double S = default;
double V = default;
var m = r;
if (g < m)
{
m = g;
}
if (b < m)
{
m = b;
}
var v = r;
if (g > v)
{
v = g;
}
if (b > v)
{
v = b;
}
var value = 100 * v / 255;
var delta = v - m;
if (v == 0.0)
{
S = 0;
}
else
{
S = 100 * delta / v;
}
if (S == 0)
{
H = 0;
}
else
{
if (r == v)
{
H = 60.0 * (g - b) / delta;
}
else if (g == v)
{
H = 120.0 + 60.0 * (b - r) / delta;
}
else if (b == v)
{
H = 240.0 + 60.0 * (r - g) / delta;
}
if (H < 0.0)
{
H = H + 360.0;
}
}
H = Math.Round(H);
S = Math.Round(S);
V = Math.Round(value);
return new HSV(H, S, V);
}
}
}

Просмотреть файл

@ -0,0 +1,16 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<OutputType>Library</OutputType>
<EnableDefaultCompileItems>False</EnableDefaultCompileItems>
<LangVersion>latest</LangVersion>
</PropertyGroup>
<Import Project="..\..\build\Base.props" />
<ItemGroup>
<Compile Include="**\*.cs" Exclude="obj\**" />
</ItemGroup>
</Project>

Просмотреть файл

@ -1,12 +1,12 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:ThemeEditor.Controls;assembly=ThemeEditor"
xmlns:converters="clr-namespace:ThemeEditor.Converters;assembly=ThemeEditor"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="256" d:DesignWidth="256">
<UserControl.Resources>
<local:HueToColorConverter x:Key="HueToColorConverter"/>
<converters:HueToColorConverter x:Key="HueToColorConverter"/>
</UserControl.Resources>
<UserControl.Styles>
<Style Selector="Slider.hue:vertical">

Просмотреть файл

@ -1,165 +1,8 @@
using System;
using System.Globalization;
using Avalonia;
using Avalonia.Controls;
using Avalonia.Data.Converters;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
using Avalonia.Media;
namespace ThemeEditor.Controls
{
public class HSV
{
public double H { get; set; }
public double S { get; set; }
public double V { get; set; }
public HSV()
{
}
public HSV(double h, double s, double v)
{
this.H = h;
this.S = s;
this.V = v;
}
public HSV(HSV hs)
{
this.H = hs.H;
this.S = hs.S;
this.V = hs.V;
}
public HSV(RGB rg)
{
HSV hs = rg.ToHSV();
this.H = hs.H;
this.S = hs.S;
this.V = hs.V;
}
public RGB ToRGB()
{
RGB rg = new RGB();
HSV hsx = new HSV(this.H, this.S, this.V);
if (hsx.S == 0)
{
rg.R = rg.G = rg.B = Math.Round(hsx.V * 2.55); return (rg);
}
hsx.S = hsx.S / 100;
hsx.V = hsx.V / 100;
hsx.H /= 60;
var i = Math.Floor(hsx.H);
var f = hsx.H - i;
var p = hsx.V * (1 - hsx.S);
var q = hsx.V * (1 - hsx.S * f);
var t = hsx.V * (1 - hsx.S * (1 - f));
switch ((int)i)
{
case 0: rg.R = hsx.V; rg.G = t; rg.B = p; break;
case 1: rg.R = q; rg.G = hsx.V; rg.B = p; break;
case 2: rg.R = p; rg.G = hsx.V; rg.B = t; break;
case 3: rg.R = p; rg.G = q; rg.B = hsx.V; break;
case 4: rg.R = t; rg.G = p; rg.B = hsx.V; break;
default: rg.R = hsx.V; rg.G = p; rg.B = q; break;
}
rg.R = Math.Round(rg.R * 255);
rg.G = Math.Round(rg.G * 255);
rg.B = Math.Round(rg.B * 255);
return rg;
}
}
public class RGB
{
public double R { get; set; }
public double G { get; set; }
public double B { get; set; }
public RGB()
{
}
public RGB(double r, double g, double b)
{
this.R = r;
this.G = g;
this.B = b;
}
public RGB(RGB rg)
{
this.R = rg.R;
this.G = rg.G;
this.B = rg.B;
}
public RGB(HSV hs)
{
RGB rg = hs.ToRGB();
this.R = rg.R;
this.G = rg.G;
this.B = rg.B;
}
public HSV ToHSV()
{
HSV hs = new HSV();
RGB rg = new RGB(this.R, this.G, this.B);
var m = rg.R;
if (rg.G < m) { m = rg.G; }
if (rg.B < m) { m = rg.B; }
var v = rg.R;
if (rg.G > v) { v = rg.G; }
if (rg.B > v) { v = rg.B; }
var value = 100 * v / 255;
var delta = v - m;
if (v == 0.0) { hs.S = 0; } else { hs.S = 100 * delta / v; }
if (hs.S == 0) { hs.H = 0; }
else
{
if (rg.R == v) { hs.H = 60.0 * (rg.G - rg.B) / delta; }
else if (rg.G == v) { hs.H = 120.0 + 60.0 * (rg.B - rg.R) / delta; }
else if (rg.B == v) { hs.H = 240.0 + 60.0 * (rg.R - rg.G) / delta; }
if (hs.H < 0.0) { hs.H = hs.H + 360.0; }
}
hs.H = Math.Round(hs.H);
hs.S = Math.Round(hs.S);
hs.V = Math.Round(value);
return hs;
}
}
public class HueToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is double hue && targetType == typeof(Color))
{
var rgb = new HSV(hue, 100, 100).ToRGB();
var color = new Color(255, (byte)rgb.R, (byte)rgb.G, (byte)rgb.B);
return color;
}
return AvaloniaProperty.UnsetValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
public class ColorPicker : UserControl
{

Просмотреть файл

@ -0,0 +1,28 @@
using System;
using System.Globalization;
using Avalonia;
using Avalonia.Data.Converters;
using Avalonia.Media;
using ThemeEditor.Colors;
namespace ThemeEditor.Converters
{
public class HueToColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if (value is double hue && targetType == typeof(Color))
{
var rgb = new HSV(hue, 100, 100).ToRGB();
var color = new Color(255, (byte)rgb.R, (byte)rgb.G, (byte)rgb.B);
return color;
}
return AvaloniaProperty.UnsetValue;
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}

Просмотреть файл

@ -22,6 +22,7 @@
<Import Project="..\..\build\EmbedXaml.props" />
<ItemGroup>
<ProjectReference Include="..\ThemeEditor.Colors\ThemeEditor.Colors.csproj" />
<ProjectReference Include="..\ThemeEditor.ViewModels\ThemeEditor.ViewModels.csproj" />
</ItemGroup>

Просмотреть файл

@ -0,0 +1,17 @@
using Xunit;
namespace ThemeEditor.Colors.UnitTests
{
public class HSVTests
{
[Fact]
public void HSV_ToRGB()
{
var hsv = new HSV(213.0, 46.0, 49.0);
var actual = hsv.ToRGB();
Assert.Equal(67.0, actual.R);
Assert.Equal(93.0, actual.G);
Assert.Equal(125.0, actual.B);
}
}
}

Просмотреть файл

@ -0,0 +1,17 @@
using Xunit;
namespace ThemeEditor.Colors.UnitTests
{
public class RGBTests
{
[Fact]
public void RGB_ToHSV()
{
var rgb = new RGB(67.0, 93.0, 125.0);
var actual = rgb.ToHSV();
Assert.Equal(213.0, actual.H);
Assert.Equal(46.0, actual.S);
Assert.Equal(49.0, actual.V);
}
}
}

Просмотреть файл

@ -0,0 +1,14 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFrameworks>netcoreapp2.1</TargetFrameworks>
</PropertyGroup>
<Import Project="..\..\build\Rx.props" />
<Import Project="..\..\build\XUnit.props" />
<ItemGroup>
<ProjectReference Include="..\..\src\ThemeEditor.Colors\ThemeEditor.Colors.csproj" />
</ItemGroup>
</Project>