add WCAG 2.1 compliant alternate color

This commit is contained in:
XtraCube committed 2025-03-12 16:45:29 -04:00
1 parent 6ab283d39c
commit 529fc89fc5
5 files changed
+97 -7

No files matched your search

@@ -202,7 +202,7 @@ public static class GameOptionsMenuPatch
{
categoryHeaderMasked.Background.color = group.GroupColor;
categoryHeaderMasked.Divider.color = group.GroupColor;
categoryHeaderMasked.Title.color = group.GroupColor.GetAlternateColor();
categoryHeaderMasked.Title.color = group.GroupColor.FindAlternateColor();
}
categoryHeaderMasked.Background.size = new Vector2(
@@ -232,10 +232,10 @@ public static class GameOptionsMenuPatch
{
if (group.GroupColor != Color.clear)
{
renderer.color = group.GroupColor.GetAlternateColor();
renderer.color = group.GroupColor.FindAlternateColor();
if (renderer.transform.parent.TryGetComponent<GameOptionButton>(out var btn))
{
btn.interactableColor = group.GroupColor.GetAlternateColor();
btn.interactableColor = group.GroupColor.FindAlternateColor();
btn.interactableHoveredColor = Color.white;
}
}
@@ -340,7 +340,7 @@ public static class LobbyViewPanePatches
viewSettingsInfoPanelRoleVariant.chanceTitle.color =
viewSettingsInfoPanelRoleVariant.chanceBackground.color =
viewSettingsInfoPanelRoleVariant.background.color =
customRole.RoleColor.GetAlternateColor();
customRole.RoleColor.FindAlternateColor();
instance.settingsInfo.Add(viewSettingsInfoPanelRoleVariant.gameObject);
num -= 0.664f;
}
@@ -384,7 +384,7 @@ public static class RoleSettingMenuPatches
}
__instance.roleHeaderSprite.color = customRole.RoleColor;
__instance.roleHeaderText.color = customRole.RoleColor.GetAlternateColor();
__instance.roleHeaderText.color = customRole.RoleColor.FindAlternateColor();
var categoryHeaderMasked = __instance.AdvancedRolesSettings.transform.Find("CategoryHeaderMasked").GetComponent<CategoryHeaderMasked>();
@@ -465,7 +465,7 @@ public static class RoleSettingMenuPatches
__instance.roleChances.Add(roleOptionSetting);
roleOptionSetting.titleText.transform.localPosition = new Vector3(-0.5376f, -0.2923f, 0f);
roleOptionSetting.titleText.color = customRole.RoleColor.GetAlternateColor();
roleOptionSetting.titleText.color = customRole.RoleColor.FindAlternateColor();
roleOptionSetting.titleText.horizontalAlignment = HorizontalAlignmentOptions.Left;
if (GameSettingMenuPatches.SelectedMod is null ||
@@ -483,7 +483,7 @@ public static class RoleSettingMenuPatches
var passiveButton = newButton.GetComponent<GameOptionButton>();
passiveButton.OnClick = new ButtonClickedEvent();
passiveButton.interactableColor = btnRend.color = customRole.RoleColor.GetAlternateColor();
passiveButton.interactableColor = btnRend.color = customRole.RoleColor.FindAlternateColor();
passiveButton.interactableHoveredColor = Color.white;
passiveButton.OnClick.AddListener((UnityAction)(() => { ChangeTab(role, __instance); }));
+89
View File
@@ -0,0 +1,89 @@
using UnityEngine;
namespace MiraAPI.Utilities;
/// <summary>
/// Extension methods for the Color struct.
/// </summary>
public static class ColorExtensions
{
/// <summary>
/// Gets the relative luminance of a color (WCAG 2.1 specification).
/// </summary>
/// <param name="color">Color to calculate luminance for.</param>
/// <returns>Relative luminance value.</returns>
public static float GetRelativeLuminance(this Color color)
{
var r = color.r <= 0.03928f ? color.r / 12.92f : Mathf.Pow((color.r + 0.055f) / 1.055f, 2.4f);
var g = color.g <= 0.03928f ? color.g / 12.92f : Mathf.Pow((color.g + 0.055f) / 1.055f, 2.4f);
var b = color.b <= 0.03928f ? color.b / 12.92f : Mathf.Pow((color.b + 0.055f) / 1.055f, 2.4f);
return 0.2126f * r + 0.7152f * g + 0.0722f * b;
}
/// <summary>
/// Calculates the contrast ratio between two colors (WCAG 2.1 specification).
/// </summary>
/// <param name="colorA">First color.</param>
/// <param name="colorB">Second color.</param>
/// <returns>Contrast ratio between the two colors.</returns>
public static float GetContrastRatio(this Color colorA, Color colorB)
{
var luminanceA = colorA.GetRelativeLuminance();
var luminanceB = colorB.GetRelativeLuminance();
return (Mathf.Max(luminanceA, luminanceB) + 0.05f) / (Mathf.Min(luminanceA, luminanceB) + 0.05f);
}
/// <summary>
/// Generates an accessible alternate color with sufficient contrast.
/// </summary>
/// <param name="color">Base color.</param>
/// <param name="desiredRatio">Target contrast ratio (default 4.5f for AA).</param>
/// <returns>Alternate color with sufficient contrast.</returns>
public static Color FindAlternateColor(this Color color, float desiredRatio = 4.5f)
{
var lightColor = FindMinimumContrastColor(color, Color.white, desiredRatio);
var darkColor = FindMinimumContrastColor(color, Color.black, desiredRatio);
return lightColor.GetContrastRatio(color) >= darkColor.GetContrastRatio(color) ? lightColor : darkColor;
}
/// <summary>
/// Finds the color with the minimum contrast ratio to the target color.
/// </summary>
/// <param name="baseColor">The base color to start from.</param>
/// <param name="targetColor">The target color to compare against.</param>
/// <param name="desiredRatio">The desired contrast ratio.</param>
/// <returns>The color with the minimum contrast ratio to the target color.</returns>
public static Color FindMinimumContrastColor(Color baseColor, Color targetColor, float desiredRatio)
{
var baseLuminance = baseColor.GetRelativeLuminance();
var isLightening = targetColor == Color.white;
var targetLuminance = isLightening
? desiredRatio * (baseLuminance + 0.05f) - 0.05f
: (baseLuminance + 0.05f) / desiredRatio - 0.05f;
if (isLightening && targetLuminance > 1f) return Color.white;
if (!isLightening && targetLuminance < 0f) return Color.black;
float low = 0f, high = 1f;
var bestColor = targetColor;
for (var i = 0; i < 10; i++)
{
var t = (low + high) / 2f;
var testColor = Color.Lerp(baseColor, targetColor, t);
var testLuminance = testColor.GetRelativeLuminance();
if ((isLightening && testLuminance >= targetLuminance) || (!isLightening && testLuminance <= targetLuminance))
{
high = t;
bestColor = testColor;
}
else
{
low = t;
}
}
return bestColor;
}
}
+1
View File
@@ -245,6 +245,7 @@ public static class Extensions
/// <param name="color">The original color.</param>
/// <param name="amount">The amount to darken or lighten the original color by between 0.0 and 1.0.</param>
/// <returns>An alternate color that has been darkened or lightened.</returns>
[Obsolete("Use FindAlternateColor for WACG compliance.")]
public static Color GetAlternateColor(this Color color, float amount = 0.45f)
{
return color.IsColorDark() ? LightenColor(color, amount) : DarkenColor(color, amount);