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

Replace default gtk color picker #1025

Open
wants to merge 23 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 18 commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
05a755b
Add color picker dialog
potatoes1286 Oct 6, 2024
17d5495
Improvements, formatting
potatoes1286 Oct 7, 2024
e51e670
formatting
potatoes1286 Oct 7, 2024
54a9472
remove debug writelines
potatoes1286 Oct 7, 2024
11c11ae
Remove collection literals
potatoes1286 Oct 7, 2024
2c4b49d
Add small mode; add ability to draw while picker active
potatoes1286 Oct 7, 2024
f0bf351
dotnet format
potatoes1286 Oct 7, 2024
81a1ef4
fix margin setting
potatoes1286 Oct 7, 2024
2222325
Fixes, improvements to ColorExtensions.cs
potatoes1286 Oct 11, 2024
e6394d8
Remove RgbColor; Change HsvColor to double
potatoes1286 Oct 11, 2024
317b07d
dotnet format
potatoes1286 Oct 11, 2024
7d8d0d1
Shift ColorExtensions.cs to CairoExtensions.cs
potatoes1286 Oct 11, 2024
ddd49f5
Fix bugs; add more methods to HsvColor.cs
potatoes1286 Oct 11, 2024
6cc8e6b
update test
potatoes1286 Oct 13, 2024
8ff7d65
add ColorTests.cs; improve CompareImages warning
potatoes1286 Oct 13, 2024
a9e0395
fixes; add opacity on unfocus
potatoes1286 Oct 13, 2024
bc1a4b5
improvements, formatting to HsvColor.cs, CairoExtensions.cs
potatoes1286 Oct 13, 2024
df12a8a
Merge branch 'master' into picker-2
potatoes1286 Oct 13, 2024
a49a978
Fix color picker always opening primary color; never secondary
potatoes1286 Nov 10, 2024
916d1e3
simplify handling of palette change; modify method inputs
potatoes1286 Nov 10, 2024
f3878ba
Streamline HsvColor
potatoes1286 Nov 10, 2024
8320855
Remove unnecessary code
potatoes1286 Nov 10, 2024
879330b
Merge remote-tracking branch 'origin/picker-2' into picker-2
potatoes1286 Nov 10, 2024
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
7 changes: 4 additions & 3 deletions Pinta.Core/Effects/ColorBgra.cs
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ public static ColorBgra Blend (ReadOnlySpan<ColorBgra> colors)
/// <returns>A ColorBgra value in premultiplied alpha form</returns>
public readonly ColorBgra ToPremultipliedAlpha () => FromBgra ((byte) (B * A / 255), (byte) (G * A / 255), (byte) (R * A / 255), A);

public static bool ColorsWithinTolerance (ColorBgra a, ColorBgra b, int tolerance)
public static int ColorDifference (ColorBgra a, ColorBgra b)
{
int diffR = a.R - b.R;
int diffG = a.G - b.G;
Expand All @@ -498,10 +498,11 @@ public static bool ColorsWithinTolerance (ColorBgra a, ColorBgra b, int toleranc
int summandA = diffA * diffA;

int sum = summandR + summandG + summandB + summandA;

return sum <= tolerance * tolerance * 4;
return sum;
}

public static bool ColorsWithinTolerance (ColorBgra a, ColorBgra b, int tolerance) => ColorDifference (a, b) <= tolerance * tolerance * 4;

/// <summary>
/// Brings the color channels from premultiplied alpha in straight alpha form.
/// This is required for direct memory manipulation when reading from Cairo surfaces
Expand Down
145 changes: 35 additions & 110 deletions Pinta.Core/Effects/HsvColor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -6,141 +6,66 @@
/////////////////////////////////////////////////////////////////////////////////

using System;
using Cairo;
using Pinta.Core.Extensions;

namespace Pinta.Core;

/// <summary>
/// Adapted from:
/// Adapted from:
/// "A Primer on Building a Color Picker User Control with GDI+ in Visual Basic .NET or C#"
/// http://www.msdnaa.net/Resources/display.aspx?ResID=2460
/// </summary>
public readonly struct HsvColor

Check warning on line 19 in Pinta.Core/Effects/HsvColor.cs

View workflow job for this annotation

GitHub Actions / build-ubuntu (7.0.x)

'HsvColor' defines operator == or operator != but does not override Object.Equals(object o)

Check warning on line 19 in Pinta.Core/Effects/HsvColor.cs

View workflow job for this annotation

GitHub Actions / build-ubuntu (8.0.x)

'HsvColor' defines operator == or operator != but does not override Object.Equals(object o)

Check warning on line 19 in Pinta.Core/Effects/HsvColor.cs

View workflow job for this annotation

GitHub Actions / build-ubuntu (8.0.x)

'HsvColor' defines operator == or operator != but does not override Object.Equals(object o)

Check warning on line 19 in Pinta.Core/Effects/HsvColor.cs

View workflow job for this annotation

GitHub Actions / build-windows

'HsvColor' defines operator == or operator != but does not override Object.Equals(object o)

Check warning on line 19 in Pinta.Core/Effects/HsvColor.cs

View workflow job for this annotation

GitHub Actions / build-windows

'HsvColor' defines operator == or operator != but does not override Object.Equals(object o)

Check warning on line 19 in Pinta.Core/Effects/HsvColor.cs

View workflow job for this annotation

GitHub Actions / build-macos

'HsvColor' defines operator == or operator != but does not override Object.Equals(object o)
{
public readonly int Hue { get; } // 0-360
public readonly int Saturation { get; } // 0-100
public readonly int Value { get; } // 0-100
public double Hue { get; init; } // 0-360
public double Sat { get; init; } // 0-1
public double Val { get; init; } // 0-1

public static bool operator == (HsvColor lhs, HsvColor rhs)
=> lhs.Hue == rhs.Hue && lhs.Saturation == rhs.Saturation && lhs.Value == rhs.Value;

public static bool operator != (HsvColor lhs, HsvColor rhs)
=> !(lhs == rhs);

public override readonly bool Equals (object? obj)
=> obj is HsvColor hsv && this == hsv;
public static bool operator == (HsvColor c1, HsvColor c2)
cameronwhite marked this conversation as resolved.
Show resolved Hide resolved
{
if (Math.Abs (c1.Hue - c2.Hue) < 0.1 &&
Math.Abs (c1.Sat - c2.Sat) < 0.001 &&
Math.Abs (c1.Val - c2.Val) < 0.001)
return true;
return false;
}

public override readonly int GetHashCode ()
=> (Hue + (Saturation << 8) + (Value << 16)).GetHashCode ();
public static bool operator != (HsvColor c1, HsvColor c2) => !(c1 == c2);

public HsvColor (int hue, int saturation, int value)
public HsvColor (double hue, double sat, double val)
{
if (hue < 0 || hue > 360)
throw new ArgumentOutOfRangeException (nameof (hue), "must be in the range [0, 360]");

if (saturation < 0 || saturation > 100)
throw new ArgumentOutOfRangeException (nameof (saturation), "must be in the range [0, 100]");
if (sat < 0 || sat > 1)
throw new ArgumentOutOfRangeException (nameof (sat), "must be in the range [0, 1]");

if (value < 0 || value > 100)
throw new ArgumentOutOfRangeException (nameof (value), "must be in the range [0, 100]");
if (val < 0 || val > 1)
throw new ArgumentOutOfRangeException (nameof (val), "must be in the range [0, 1]");

Hue = hue;
Saturation = saturation;
Value = value;
Sat = sat;
Val = val;
}

// public static HsvColor FromColor(Color color)
// {
// RgbColor rgb = new RgbColor(color.R, color.G, color.B);
// return rgb.ToHsv();
// }
//
// public Color ToColor()
// {
// RgbColor rgb = ToRgb();
// return Color.FromArgb(rgb.Red, rgb.Green, rgb.Blue);
// }

public readonly RgbColor ToRgb ()
{
// HsvColor contains values scaled as in the color wheel.
// Scale Hue to be between 0 and 360. Saturation
// and value scale to be between 0 and 1.
double h = (double) Hue % 360;
double s = (double) Saturation / 100;
double v = (double) Value / 100;

double r = 0;
double g = 0;
double b = 0;

if (s == 0) {
// If s is 0, all colors are the same.
// This is some flavor of gray.
r = v;
g = v;
b = v;
} else {
// The color wheel consists of 6 sectors.
// Figure out which sector you're in.
double sectorPos = h / 60;
int sectorNumber = (int) (Math.Floor (sectorPos));
public static HsvColor FromColor (Color c) => c.ToHsv ();
public Color ToColor (double alpha = 1) => Color.FromHsv (this);
cameronwhite marked this conversation as resolved.
Show resolved Hide resolved

// get the fractional part of the sector.
// That is, how many degrees into the sector
// are you?
double fractionalSector = sectorPos - sectorNumber;
public static HsvColor FromRgbD (double r, double g, double b) => new Color (r, g, b).ToHsv ();
cameronwhite marked this conversation as resolved.
Show resolved Hide resolved

// Calculate values for the three axes
// of the color.
double p = v * (1 - s);
double q = v * (1 - (s * fractionalSector));
double t = v * (1 - (s * (1 - fractionalSector)));
public static HsvColor FromRgbI (int r, int g, int b) => new Color (r / 255.0, g / 255.0, b / 255.0).ToHsv ();

// Assign the fractional colors to r, g, and b
// based on the sector the angle is in.
switch (sectorNumber) {
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;

case 5:
r = v;
g = p;
b = q;
break;
}
}
// return an RgbColor structure, with values scaled
// to be between 0 and 255.
return new RgbColor ((int) (r * 255), (int) (g * 255), (int) (b * 255));
public static HsvColor FromBgra (ColorBgra c) => new Color (c.R / 255.0, c.G / 255.0, c.B / 255.0).ToHsv ();
cameronwhite marked this conversation as resolved.
Show resolved Hide resolved
public ColorBgra ToBgra ()
{
var c = this.ToColor ();
return ColorBgra.FromBgr ((byte) (c.B * 255.0), (byte) (c.G * 255.0), (byte) (c.R * 255.0));
}

public override readonly string ToString ()
=> $"({Hue}, {Saturation}, {Value})";
=> $"({Hue:F2}, {Sat:F2}, {Val:F2})";

public override int GetHashCode ()
=> ((int) Hue + ((int) Sat << 8) + ((int) Val << 16)).GetHashCode ();
}
115 changes: 0 additions & 115 deletions Pinta.Core/Effects/RgbColor.cs

This file was deleted.

13 changes: 6 additions & 7 deletions Pinta.Core/Effects/UnaryPixelOps.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@
using System;
using System.Collections.Immutable;
using System.Linq;
using Cairo;
using Pinta.Core.Extensions;

namespace Pinta.Core;

Expand Down Expand Up @@ -132,7 +134,7 @@ public SetChannel (int channel, byte setValue)
/// <summary>
/// Specialization of SetChannel that sets the alpha channel.
/// </summary>
/// <remarks>This class depends on the system being litte-endian with the alpha channel
/// <remarks>This class depends on the system being litte-endian with the alpha channel
/// occupying the 8 most-significant-bits of a ColorBgra instance.
/// By the way, we use addition instead of bitwise-OR because an addition can be
/// perform very fast (0.5 cycles) on a Pentium 4.</remarks>
Expand Down Expand Up @@ -669,19 +671,16 @@ public override ColorBgra Apply (in ColorBgra src_color)
color.G = Utility.ClampToByte ((intensity * 1024 + (color.G - intensity) * sat_factor) >> 10);
color.B = Utility.ClampToByte ((intensity * 1024 + (color.B - intensity) * sat_factor) >> 10);

HsvColor hsvColor = (new RgbColor (color.R, color.G, color.B)).ToHsv ();
int newHue = hsvColor.Hue;
HsvColor hsvColor = HsvColor.FromBgra (color);
int newHue = (int) hsvColor.Hue;

newHue += hue_delta;

while (newHue < 0) { newHue += 360; }

while (newHue > 360) { newHue -= 360; }

hsvColor = new HsvColor (newHue, hsvColor.Saturation, hsvColor.Value);

RgbColor rgbColor = hsvColor.ToRgb ();
ColorBgra newColor = ColorBgra.FromBgr ((byte) rgbColor.Blue, (byte) rgbColor.Green, (byte) rgbColor.Red);
ColorBgra newColor = (hsvColor with { Hue = newHue }).ToBgra ();
newColor = blend_op.Apply (newColor);
newColor.A = color.A;

Expand Down
Loading
Loading