From 0067aee519d9b447b99f112a9c3f6330b34e42ca Mon Sep 17 00:00:00 2001 From: dotCooCoo Date: Sun, 1 Nov 2026 14:45:35 -0800 Subject: [PATCH] Tests: the tool tip's box keeps the theme's fill and contrast The test for #3818 checked the tool tip's text color and the style's window fill. It now also checks the fill of the box drawn behind the tool tip's text, and that the text and the box have a contrast ratio of at least 4.5, for every brightness and scheme. --- crates/ui-egui/src/theme.rs | 39 +++++++++++++++++++++++++++++++++---- 1 file changed, 35 insertions(+), 4 deletions(-) diff --git a/crates/ui-egui/src/theme.rs b/crates/ui-egui/src/theme.rs index 3b1a0524d..0ca446b4d 100644 --- a/crates/ui-egui/src/theme.rs +++ b/crates/ui-egui/src/theme.rs @@ -705,19 +705,50 @@ mod tests { ui.button("Hover me").on_hover_text("Tip text"); }); out.textures_delta.clear(); - tip = out.shapes.iter().find_map(|c| match &c.shape { - egui::Shape::Text(s) if s.galley.text() == "Tip text" => Some(s.fallback_color), + // The tool tip's text color, and the fill of the box drawn behind it. + let mut shapes: Vec<&egui::Shape> = Vec::new(); + let mut open: Vec<&egui::Shape> = out.shapes.iter().rev().map(|c| &c.shape).collect(); + while let Some(shape) = open.pop() { + match shape { + egui::Shape::Vec(inner) => open.extend(inner.iter().rev()), + shape => shapes.push(shape), + } + } + tip = shapes.iter().enumerate().find_map(|(n, shape)| match shape { + egui::Shape::Text(s) if s.galley.text() == "Tip text" => { + let fill = shapes[..n].iter().rev().find_map(|behind| match behind { + egui::Shape::Rect(r) if r.rect.contains(s.pos) && r.fill.a() > 0 => Some(r.fill), + _ => None, + }); + Some((s.fallback_color, fill)) + } _ => None, }); } let v = ctx.global_style().visuals.clone(); - assert_eq!((v.window_fill, v.override_text_color), (t.panel, Some(t.text)), "{scheme:?} {b:?}, system {first:?} then {then:?}"); - assert_eq!(tip, Some(t.text), "{scheme:?} {b:?}, system {first:?} then {then:?}: the tool tip's text"); + let what = format!("{scheme:?} {b:?}, system {first:?} then {then:?}"); + assert_eq!((v.window_fill, v.override_text_color), (t.panel, Some(t.text)), "{what}"); + assert_eq!(tip, Some((t.text, Some(t.panel))), "{what}: the tool tip's text and box"); + assert!(contrast(t.text, t.panel) >= 4.5, "{what}: the tool tip's text against its box, {}", contrast(t.text, t.panel)); } } } } + /// The contrast ratio of two opaque colors, from 1 (the same) to 21 (black on white), as WCAG 2 + /// defines it. + fn contrast(a: egui::Color32, b: egui::Color32) -> f32 { + let luminance = |c: egui::Color32| { + let channel = |v: u8| { + let v = f32::from(v) / 255.0; + if v <= 0.040_45 { v / 12.92 } else { ((v + 0.055) / 1.055).powf(2.4) } + }; + 0.2126 * channel(c.r()) + 0.7152 * channel(c.g()) + 0.0722 * channel(c.b()) + }; + let (a, b) = (luminance(a), luminance(b)); + (a.max(b) + 0.05) / (a.min(b) + 0.05) + } + /// Changing brightness keeps the interface settings made after the theme was applied, such as /// General › Show Tool Tips' delay. #[test]