Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

OkHsv, OkHsl #43

Draft
wants to merge 2 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions src/ColorPicker.AvaloniaUI/DualPickerControlBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ public class DualPickerControlBase : PickerControlBase, ISecondColorStorage, IHi
{
public static readonly StyledProperty<ColorState> SecondColorStateProperty =
AvaloniaProperty.Register<DualPickerControlBase, ColorState>(
nameof(SecondColorState), new ColorState(1, 1, 1, 1, 0, 0, 1, 0, 0, 1));
nameof(SecondColorState), new ColorState(1, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1));

public static readonly StyledProperty<ColorState> HintColorStateProperty =
AvaloniaProperty.Register<DualPickerControlBase, ColorState>(
nameof(HintColorState), new ColorState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0));
nameof(HintColorState), new ColorState(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));

public static readonly StyledProperty<Color> SecondaryColorProperty =
AvaloniaProperty.Register<DualPickerControlBase, Color>(
Expand Down
2 changes: 1 addition & 1 deletion src/ColorPicker.AvaloniaUI/PickerControlBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ public class PickerControlBase : TemplatedControl, IColorStateStorage
{
public static readonly StyledProperty<ColorState> ColorStateProperty =
AvaloniaProperty.Register<PickerControlBase, ColorState>(
nameof(ColorState), new ColorState(0, 0, 0, 1, 0, 0, 0, 0, 0, 0));
nameof(ColorState), new ColorState(0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0));

public static readonly StyledProperty<Color> SelectedColorProperty =
AvaloniaProperty.Register<PickerControlBase, Color>(
Expand Down
53 changes: 39 additions & 14 deletions src/ColorPicker.AvaloniaUI/SquareSlider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using Avalonia.Reactive;
using ColorPicker.AvaloniaUI;
using ColorPicker.Models;
using ColorPicker.Models.ColorSpaces;

namespace ColorPicker.UserControls;

Expand Down Expand Up @@ -50,9 +51,8 @@ public NotifyableColor Color
set => SetValue(ColorProperty, value);
}

private Func<double, double, double, Tuple<double, double, double>> colorSpaceConversionMethod =
ColorSpaceHelper.HsvToRgb;

private Action recalculateGradientMethod;

private IDisposable headXBinding;
private IDisposable headYBinding;
private Image image;
Expand Down Expand Up @@ -111,6 +111,8 @@ public SquareSlider()
{
GradientBitmap = new WriteableBitmap(new PixelSize(32, 32), new Vector(96, 96), PixelFormats.Rgb24);
PseudoClasses.Set(":hsv", true);

recalculateGradientMethod = RecalculateGradientHsv;
}

protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
Expand All @@ -119,7 +121,7 @@ protected override void OnApplyTemplate(TemplateAppliedEventArgs e)
image = e.NameScope.Find<Image>("PART_GradientImage");

UpdateHeadBindings(this, PickerType);
RecalculateGradient();
recalculateGradientMethod();
}

protected override void OnPointerPressed(PointerPressedEventArgs e)
Expand All @@ -142,7 +144,31 @@ protected override void OnPointerMoved(PointerEventArgs e)
UpdatePos(e.GetPosition(this));
}

private void RecalculateGradient()
private void RecalculateGradientHsv()
{
var w = GradientBitmap.PixelSize.Width;
var h = GradientBitmap.PixelSize.Height;
var hue = Hue;
var pixels = new byte[w * h * 3];
for (var j = 0; j < h; j++)
for (var i = 0; i < w; i++)
{
var rgb = RgbHelper.HsvToRgb(hue, i / (double)(w - 1), (h - 1 - j) / (double)(h - 1));
var pos = (j * h + i) * 3;
pixels[pos] = (byte)(rgb.R * 255);
pixels[pos + 1] = (byte)(rgb.G * 255);
pixels[pos + 2] = (byte)(rgb.B * 255);
}

using (var framebuffer = GradientBitmap.Lock())
{
framebuffer.WritePixels(0, 0, w, h, pixels);
}

image.InvalidateVisual();
}

private void RecalculateGradientHsl()
{
var w = GradientBitmap.PixelSize.Width;
var h = GradientBitmap.PixelSize.Height;
Expand All @@ -151,12 +177,11 @@ private void RecalculateGradient()
for (var j = 0; j < h; j++)
for (var i = 0; i < w; i++)
{
var rgbtuple = colorSpaceConversionMethod(hue, i / (double)(w - 1), (h - 1 - j) / (double)(h - 1));
double r = rgbtuple.Item1, g = rgbtuple.Item2, b = rgbtuple.Item3;
var rgb = RgbHelper.HslToRgb(hue, i / (double)(w - 1), (h - 1 - j) / (double)(h - 1));
var pos = (j * h + i) * 3;
pixels[pos] = (byte)(r * 255);
pixels[pos + 1] = (byte)(g * 255);
pixels[pos + 2] = (byte)(b * 255);
pixels[pos] = (byte)(rgb.R * 255);
pixels[pos + 1] = (byte)(rgb.G * 255);
pixels[pos + 2] = (byte)(rgb.B * 255);
}

using (var framebuffer = GradientBitmap.Lock())
Expand All @@ -171,11 +196,11 @@ private static void OnColorSpaceChanged(AvaloniaPropertyChangedEventArgs<PickerT
{
var sender = (SquareSlider)args.Sender;
if (args.NewValue.Value == PickerType.HSV)
sender.colorSpaceConversionMethod = ColorSpaceHelper.HsvToRgb;
sender.recalculateGradientMethod = sender.RecalculateGradientHsv;
else
sender.colorSpaceConversionMethod = ColorSpaceHelper.HslToRgb;
sender.recalculateGradientMethod = sender.RecalculateGradientHsl;

sender.RecalculateGradient();
sender.recalculateGradientMethod();
sender.PseudoClasses.Set(":hsv", args.NewValue.Value == PickerType.HSV);
sender.PseudoClasses.Set(":hsl", args.NewValue.Value == PickerType.HSL);
UpdateHeadBindings(sender, args.NewValue.Value);
Expand Down Expand Up @@ -208,7 +233,7 @@ private static void UpdateHeadBindings(SquareSlider squareSlider, PickerType pic

private static void OnHueChanged(AvaloniaPropertyChangedEventArgs<double> args)
{
((SquareSlider)args.Sender).RecalculateGradient();
((SquareSlider)args.Sender).recalculateGradientMethod();
}

private void UpdatePos(Point pos)
Expand Down
20 changes: 9 additions & 11 deletions src/ColorPicker.AvaloniaUI/UIExtensions/HslColorSlider.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Avalonia;
using Avalonia.Media;
using ColorPicker.Models;
using ColorPicker.Models.ColorSpaces;

namespace ColorPicker.UIExtensions;

Expand Down Expand Up @@ -73,23 +74,20 @@ private Color GetColorForSelectedArgb(int value)
{
case "H":
{
var rgbtuple = ColorSpaceHelper.HslToRgb(value, 1.0, 0.5);
double r = rgbtuple.Item1, g = rgbtuple.Item2, b = rgbtuple.Item3;
return Color.FromArgb(255, (byte)(r * 255), (byte)(g * 255), (byte)(b * 255));
var rgb = RgbHelper.HslToRgb(value, 1.0, 0.5);
return Color.FromArgb(255, (byte)(rgb.R * 255), (byte)(rgb.G * 255), (byte)(rgb.B * 255));
}
case "S":
{
var rgbtuple =
ColorSpaceHelper.HslToRgb(CurrentColorState.HSL_H, value / 255.0, CurrentColorState.HSL_L);
double r = rgbtuple.Item1, g = rgbtuple.Item2, b = rgbtuple.Item3;
return Color.FromArgb(255, (byte)(r * 255), (byte)(g * 255), (byte)(b * 255));
var rgb =
RgbHelper.HslToRgb(CurrentColorState.HSL_H, value / 255.0, CurrentColorState.HSL_L);
return Color.FromArgb(255, (byte)(rgb.R * 255), (byte)(rgb.G * 255), (byte)(rgb.B * 255));
}
case "L":
{
var rgbtuple =
ColorSpaceHelper.HslToRgb(CurrentColorState.HSL_H, CurrentColorState.HSL_S, value / 255.0);
double r = rgbtuple.Item1, g = rgbtuple.Item2, b = rgbtuple.Item3;
return Color.FromArgb(255, (byte)(r * 255), (byte)(g * 255), (byte)(b * 255));
var rgb =
RgbHelper.HslToRgb(CurrentColorState.HSL_H, CurrentColorState.HSL_S, value / 255.0);
return Color.FromArgb(255, (byte)(rgb.R * 255), (byte)(rgb.G * 255), (byte)(rgb.B * 255));
}
default:
return Color.FromArgb(255, (byte)(CurrentColorState.RGB_R * 255), (byte)(CurrentColorState.RGB_G * 255),
Expand Down
20 changes: 9 additions & 11 deletions src/ColorPicker.AvaloniaUI/UIExtensions/HsvColorSlider.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using Avalonia;
using Avalonia.Media;
using ColorPicker.Models;
using ColorPicker.Models.ColorSpaces;

namespace ColorPicker.UIExtensions;

Expand Down Expand Up @@ -58,23 +59,20 @@ private Color GetColorForSelectedArgb(int value)
{
case "H":
{
var rgbtuple = ColorSpaceHelper.HsvToRgb(value, 1.0, 1.0);
double r = rgbtuple.Item1, g = rgbtuple.Item2, b = rgbtuple.Item3;
return Color.FromArgb(255, (byte)(r * 255), (byte)(g * 255), (byte)(b * 255));
var rgb = RgbHelper.HsvToRgb(value, 1.0, 1.0);
return Color.FromArgb(255, (byte)(rgb.R * 255), (byte)(rgb.G * 255), (byte)(rgb.B * 255));
}
case "S":
{
var rgbtuple =
ColorSpaceHelper.HsvToRgb(CurrentColorState.HSV_H, value / 255.0, CurrentColorState.HSV_V);
double r = rgbtuple.Item1, g = rgbtuple.Item2, b = rgbtuple.Item3;
return Color.FromArgb(255, (byte)(r * 255), (byte)(g * 255), (byte)(b * 255));
var rgb =
RgbHelper.HsvToRgb(CurrentColorState.HSV_H, value / 255.0, CurrentColorState.HSV_V);
return Color.FromArgb(255, (byte)(rgb.R * 255), (byte)(rgb.G * 255), (byte)(rgb.B * 255));
}
case "V":
{
var rgbtuple =
ColorSpaceHelper.HsvToRgb(CurrentColorState.HSV_H, CurrentColorState.HSV_S, value / 255.0);
double r = rgbtuple.Item1, g = rgbtuple.Item2, b = rgbtuple.Item3;
return Color.FromArgb(255, (byte)(r * 255), (byte)(g * 255), (byte)(b * 255));
var rgb =
RgbHelper.HsvToRgb(CurrentColorState.HSV_H, CurrentColorState.HSV_S, value / 255.0);
return Color.FromArgb(255, (byte)(rgb.R * 255), (byte)(rgb.G * 255), (byte)(rgb.B * 255));
}
default:
return Color.FromArgb((byte)(CurrentColorState.A * 255), (byte)(CurrentColorState.RGB_R * 255),
Expand Down
4 changes: 4 additions & 0 deletions src/ColorPicker.Models/ColorPicker.Models.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,8 @@
</None>
</ItemGroup>





</Project>
29 changes: 29 additions & 0 deletions src/ColorPicker.Models/ColorSliders/ColorSliderGradientPoint.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
using System;
using ColorPicker.Models.Colors;

namespace ColorPicker.Models.ColorSliders;

public struct ColorSliderGradientPoint
{
public double R;
public double G;
public double B;
public double A = 1.0;
public double Position;

public ColorSliderGradientPoint(double r, double g, double b, double position)
{
R = r;
G = g;
B = b;
Position = position;
}

public ColorSliderGradientPoint(Rgb rgb, double position)
{
R = rgb.R;
G = rgb.G;
B = rgb.B;
Position = position;
}
}
25 changes: 25 additions & 0 deletions src/ColorPicker.Models/ColorSliders/ColorSliderType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
namespace ColorPicker.Models.ColorSliders;

public enum ColorSliderType
{
RgbRed,
RgbGreen,
RgbBlue,
Alpha,

HsvHslHue,

HsvSaturation,
HsvValue,

HslSaturation,
HslLightness,

OkHsvHue,
OkHsvSaturation,
OkHsvValue,

OkHslHue,
OkHslSaturation,
OkHslLightness,
}
46 changes: 46 additions & 0 deletions src/ColorPicker.Models/ColorSliders/ColorSliderTypeFactory.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using System;
using ColorPicker.Models.ColorSliders.Types;

namespace ColorPicker.Models.ColorSliders;

public static class ColorSliderTypeFactory
{
public static IColorSliderType Get(ColorSliderType type)
{
switch (type)
{
case ColorSliderType.RgbRed:
return new RgbRedColorSliderType();
case ColorSliderType.RgbGreen:
return new RgbGreenColorSliderType();
case ColorSliderType.RgbBlue:
return new RgbBlueColorSliderType();
case ColorSliderType.Alpha:
return new AlphaColorSliderType();
case ColorSliderType.HsvHslHue:
return new HsvHslHueColorSliderType();
case ColorSliderType.HsvSaturation:
return new HsvSaturationColorSliderType();
case ColorSliderType.HsvValue:
return new HsvValueColorSliderType();
case ColorSliderType.HslSaturation:
return new HslSaturationColorSliderType();
case ColorSliderType.HslLightness:
return new HslLightnessColorSliderType();
case ColorSliderType.OkHsvHue:
return new OkHsvHueColorSliderType();
case ColorSliderType.OkHsvSaturation:
return new OkHsvSaturationColorSliderType();
case ColorSliderType.OkHsvValue:
return new OkHsvValueColorSliderType();
case ColorSliderType.OkHslHue:
return new OkHslHueColorSliderType();
case ColorSliderType.OkHslSaturation:
return new OkHslSaturationColorSliderType();
case ColorSliderType.OkHslLightness:
return new OkHslLightnessColorSliderType();
default:
throw new ArgumentOutOfRangeException(nameof(type));
}
}
}
10 changes: 10 additions & 0 deletions src/ColorPicker.Models/ColorSliders/IColorSliderType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
using System;
using System.Collections.Generic;

namespace ColorPicker.Models.ColorSliders;

public interface IColorSliderType
{
List<ColorSliderGradientPoint> CalculateRgbGradient(ColorState currentColorState);
bool RefreshGradient { get; }
}
17 changes: 17 additions & 0 deletions src/ColorPicker.Models/ColorSliders/Types/AlphaColorSliderType.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
using System.Collections.Generic;

namespace ColorPicker.Models.ColorSliders.Types;

internal class AlphaColorSliderType : IColorSliderType
{
public List<ColorSliderGradientPoint> CalculateRgbGradient(ColorState state)
{
return new List<ColorSliderGradientPoint>()
{
new ColorSliderGradientPoint(state.RGB_R, state.RGB_G, state.RGB_B, 0.0) { A = 0 },
new ColorSliderGradientPoint(state.RGB_R, state.RGB_G, state.RGB_B, 1.0) { A = 1 }
};
}

public bool RefreshGradient => true;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.Collections.Generic;
using ColorPicker.Models.ColorSpaces;

namespace ColorPicker.Models.ColorSliders.Types;

internal class HslLightnessColorSliderType : IColorSliderType
{
public List<ColorSliderGradientPoint> CalculateRgbGradient(ColorState state)
{
return new List<ColorSliderGradientPoint>()
{
new ColorSliderGradientPoint(RgbHelper.HslToRgb(state.HSL_H, state.HSL_S, 0), 0),
new ColorSliderGradientPoint(RgbHelper.HslToRgb(state.HSL_H, state.HSL_S, 0.25), 0.25),
new ColorSliderGradientPoint(RgbHelper.HslToRgb(state.HSL_H, state.HSL_S, 0.5), 0.5),
new ColorSliderGradientPoint(RgbHelper.HslToRgb(state.HSL_H, state.HSL_S, 0.75), 0.75),
new ColorSliderGradientPoint(RgbHelper.HslToRgb(state.HSL_H, state.HSL_S, 1), 1)
};
}

public bool RefreshGradient => true;
}
Loading