Core - Fix color gradient and utility bugs found by the tests (#914)

* Profile adaption - Fix arrow keys section including Page Down

- The arrow keys keyboard section now starts at Arrow Up instead of the key before it (Page Down)
- Updated the keyboard section test to expect only the four arrow keys

* Color quantizer - Let fully saturated colors be vibrant and grays be muted

- The saturation limits of the color types are now inclusive, so 100% saturated colors count as vibrant and 0% saturated colors count as muted
- The lightness limits stay exclusive so pure black and white are still left out
- Updated the quantizer tests to match

* Color gradients - Fix stop placement, seamless toggling and list events

- Stops on an occupied position now move down 0.001 instead of 0.002 (rounding error in the distance check)
- Flip, rotate, spread and interpolate move all stops together, so a stop can take a position another stop is leaving
- Spreading or randomizing a single stop puts it at 0 instead of NaN
- ToggleSeamless does nothing on an empty gradient and caps stretched stops at 1 instead of 100
- RemoveAt reports the removed stop and its index
- Insert links the stop like Add does and raises the add before the move
- Remove, RemoveAt, Clear and replacing a stop through the indexer unlink and stop listening to the actual removed stop
- Copying from a list of stops sorts them by position
- Obsolete GetPositionsArray no longer skips the seamless positions, obsolete GetColor picks the right colors after a repeat
- Updated the gradient tests to match

* Core - Fix small color, enum, string and type utility bugs

- Darken keeps the alpha of the color
- GetAllValuesAndDescriptions(Type) uses the [Description] attribute like the generic version
- UrlFriendly cuts titles at 80 characters instead of 81
- RemapInternationalCharToAscii knows both cases of r, l, d, thorn, sharp s, h and j with accents
- IsGenericType returns false instead of throwing when the base type is not generic
- IsCastableFrom also finds conversion operators declared on the target type
- GetDisplayName keeps the brackets of array types when humanizing
- Updated the utility tests to match
This commit is contained in:
RobertBeekman authored and GitHub committed 2026-10-24 15:53:52 +02:00
1 parent 6df81b19b1
commit 63186ee06d
15 files changed
+274 -201

No files matched your search

@@ -67,7 +67,7 @@ public static class SKColorExtensions
{
c.ToHsl(out float h, out float s, out float l);
l *= 1f - amount;
return SKColor.FromHsl(h, s, l);
return SKColor.FromHsl(h, s, l, c.Alpha);
}
private static byte ClampToByte(float value)
+15 -4
View File
@@ -55,7 +55,7 @@ public static class TypeExtensions
if (type == null)
return false;
return type.BaseType?.GetGenericTypeDefinition() == genericType;
return type.BaseType is {IsGenericType: true} baseType && baseType.GetGenericTypeDefinition() == genericType;
}
/// <summary>
@@ -111,9 +111,7 @@ public static class TypeExtensions
return true;
if (PrimitiveTypeConversions.ContainsKey(to) && PrimitiveTypeConversions[to].Contains(from))
return true;
bool castable = from.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Any(m => m.ReturnType == to && (m.Name == "op_Implicit" || m.Name == "op_Explicit"));
return castable;
return HasConversionOperator(to, from);
}
/// <summary>
@@ -141,6 +139,15 @@ public static class TypeExtensions
return 0;
}
private static bool HasConversionOperator(Type to, Type from)
{
// A conversion operator can be declared on either of the two types
return from.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Any(m => m.ReturnType == to && (m.Name == "op_Implicit" || m.Name == "op_Explicit")) ||
to.GetMethods(BindingFlags.Public | BindingFlags.Static)
.Any(m => m.ReturnType == to && (m.Name == "op_Implicit" || m.Name == "op_Explicit") && m.GetParameters()[0].ParameterType.IsAssignableFrom(from));
}
/// <summary>
/// Returns the default value of the given type
/// </summary>
@@ -200,6 +207,10 @@ public static class TypeExtensions
/// <returns></returns>
public static string GetDisplayName(this Type type, bool humanize = false)
{
// Name the element type separately so humanizing doesn't drop the brackets
if (type.IsArray)
return $"{type.GetElementType()!.GetDisplayName(humanize)}[{new string(',', type.GetArrayRank() - 1)}]";
if (!type.IsGenericType)
{
string displayValue = TypeKeywords.TryGetValue(type, out string? keyword) ? keyword! : type.Name;