Skip to content

[Proposal] New ColorHelper API #756

@Avid29

Description

@Avid29

Approved from Discussion

https://discord.com/channels/372137812037730304/1430217634204356608

Problem Statement

The current ColorHelper API is unintuitive for an object-oriented environment and poorly utilizes the HsvColor and HslColor.

Overview

Proposed ColorHelper API

public static class ColorHelper
{
  public static bool TryParseColor(string colorString, out Color color);

  public static bool TryParseHexColor(string hexString, out Color color);

  public static bool TryParseHslColor(string hslColor, out Color color);

  public static bool TryParseHsvColor(string hsvColor, out Color color);

  public static bool TryParseScreenColor(string screenColor, out Color color);

  public static bool TryParseColorName(string colorName, out Color color);

  public static Color ParseColor(string colorString);

  public static Color ParseHexColor(string hexString);

  public static Color ParseHslColor(string hslColor);

  public static Color ParseHsvColor(string hsvColor);

  public static Color ParseScreenColor(string screenColor);

  public static Color ParseColorName(string colorName);
}

public static class ColorExtensions
{
  public static int ToInt(this Color color);  

  public static HslColor ToHsl(this Color color);

  public static HsvColor ToHsv(this Color color);
}

public struct HslColor
{
  // The properties will apply clamps on set to restrict the values to a valid range
  public double H { readonly get; set;}
  public double S { readonly get; set;}
  public double L { readonly get; set;}
  public double A { readonly get; set;}

  public static HslColor Create(double hue, double saturation, double lightness, double alpha = 1);

  public Color ToColor();

  public string ToString(); // hsv(hue, sat, lightness)

  // Cast operators
  public static implicit operator Color(HslColor color);
  public static explicit operator HslColor(Color color);
  public static explicit operator HslColor(HsvColor color);
}

public struct HsvColor
{
  // The properties will apply clamps on set to restrict the values to a valid range
  public double H { readonly get; set;}
  public double S { readonly get; set;}
  public double V { readonly get; set;}
  public double A { readonly get; set;}

  public static HsvColor Create(double hue, double saturation, double value, double alpha = 1);

  public Color ToColor();

  public string ToString(); // hsv(hue, sat, value)

  // Cast operators
  public static implicit operator Color(HsvColor color);
  public static explicit operator HsvColor(Color color);
  public static explicit operator HsvColor(HslColor color);
}

Breaking Changes

Due to its nature as an API change, this proposal would introduce breaking changes. However, each of these changes can be easily remedied by a simple change in function call or by utilizing a casting operation.

Method changes

(These will be marked obsolete, but will still be available until the next major version)

  • ToHex(this Color color) - Redundant with ToString()
  • ToColor(this string colorString) - Replaced with ColorHelper.ParseColor(string colorString)
  • ColorHelper.FromHsl(double hue, ...) - Replaced with (Color)HslColor.Create(double hue, ...) (NOTE: The cast could be done implicitly)
  • ColorHelper.FromHsv(double hue, ...) - Replaced with (Color)HsvColor.Create(double hue, ...) (NOTE: The cast could be done implicitly)

Also, the ToColor function only supported hex, screen color, and color name parsing. In the current version I have drafted, ParseColor also only supports these and does not support hsl or hsv, even though in my opinion it probably should... This would result in a changed behavior, and therefore I have not yet added it.

Struct changes

All members of the HslColor and HsvColor structs were public fields with no constraints in value.
These have been replaced with properties that have been restricted to valid ranges for the property. If a developer had been relying on invalid ranges or behavior related to the members being fields, this will no longer work.

In the following example, hsl.H would previously be 500 but will now be clamped to 360.

HslColor hsl = default;
hsl.H = 500;

These changes also mean that the struct must be given a value before being used.

For example, the following code would be valid before but would now say that hsl is not defined on the second line.

HslColor hsl;
hsl.H = 240;

Metadata

Metadata

Assignees

No one assigned

    Labels

    experiment 🧪Used to track issues that are experiments (or their linked discussions)

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions