diff --git a/HellionChat/Ui/StyleEngine/TypeScale.cs b/HellionChat/Ui/StyleEngine/TypeScale.cs new file mode 100644 index 0000000..ca8f3a5 --- /dev/null +++ b/HellionChat/Ui/StyleEngine/TypeScale.cs @@ -0,0 +1,42 @@ +namespace HellionChat.Ui.StyleEngine; + +internal enum TypeRole +{ + Body, + Sender, + Header, + Meta, +} + +// Named sizes derived from one base, so a role means the same thing wherever it +// is drawn. +// +// Three of the four share the base size. That is deliberate: what sets the +// sender apart is weight and what sets the header apart is small caps with wide +// tracking, and neither is a size. Solving those with size instead would make +// the log look like a ransom note. Only the meta role -- timestamps and the +// header's trailing detail -- steps down, because it is meant to be skipped over +// rather than read. +// +// The factors are defaults, not constants. The master spec puts typography under +// theme control rather than user control, and ThemeTypography already exists as +// the extension point for exactly that. A const would wall it off. What is +// deliberately absent either way is a user-facing slider per role. +internal static class TypeScale +{ + // Below this a timestamp stops being readable at any display scale. + internal const float MinPt = 7f; + + private static readonly float[] Factors = + [ + 1.00f, // Body -- the reference every other role is stated against + 1.00f, // Sender -- set apart by weight, see FontManager.SenderWeight + 1.00f, // Header -- set apart by small caps and tracking + 0.82f, // Meta -- timestamps, and the world and clock in the header + ]; + + internal static float FactorOf(TypeRole role) => Factors[(int)role]; + + internal static float SizePtOf(TypeRole role, float basePt) => + TypeScaleMath.Resolve(basePt, FactorOf(role), MinPt); +}