返回 CodeWhale
1 //! The native port of `rig.js::resolveLook`, shared by the GPUI painter and
2 //! legibility metrics. The web boundary check guards parity with the reference.
3
4 use super::rig::Role;
5
6 /// How a named shape is filled.
7 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
8 pub enum Fill {
9 Solid(u32),
10 /// The body's two-stop gradient at 135°: first stop top-left.
11 Gradient([u32; 2]),
12 }
13
14 /// The light eye/throat apertures the color whale paints.
15 pub const APERTURE: u32 = 0xfaf8f5;
16
17 /// The contrast rim a surface over an unknown backdrop paints behind the
18 /// silhouette (see [`keyline_stroke`]): a deep-sea ink, darker than every
19 /// body stop, so the edge holds on paper, mid-grey and photographs while
20 /// the body itself holds on dark wallpaper. A light keyline on paper
21 /// wallpaper measures 1.00:1, so this stays dark.
22 pub const RIM: u32 = 0x08101c;
23 /// The rim's opacity. Solid enough to carry 3:1 against mid-grey.
24 pub const RIM_ALPHA: f64 = 0.95;
25
26 /// The light hairline one device pixel outside the rim: the cursor trick.
27 /// The dark rim alone sinks into dark and mid-tone wallpaper (a worst median
28 /// edge of 2.2:1 over real photographs); a light line alone vanishes on
29 /// paper. Together one of the two always separates the form. A crisp
30 /// stroke, never blurred: it is a keyline, not a glow.
31 pub const HALO: u32 = 0xfaf8f5;
32 /// The hairline's opacity.
33 pub const HALO_ALPHA: f64 = 0.85;
34 /// Below this side, in logical pixels, the hairline fills the C's inner
35 /// opening and reads as a grey badge, so it is left off. The floating
36 /// companion, the one carrier over an unknown desktop, renders far above it.
37 pub const HALO_MIN_SIDE: f64 = 32.;
38
39 /// The body gradient stops for a theme.
40 pub fn body(dark: bool) -> [u32; 2] {
41 if dark {
42 [0x3594d8, 0x2b70d5]
43 } else {
44 [0x1e8fd8, 0x0b48bb]
45 }
46 }
47
48 /// The color fill for a shape role, or `None` for roles that never paint
49 /// on their own (compound cutouts).
50 pub fn fill(role: Role, dark: bool) -> Option<Fill> {
51 Some(match role {
52 Role::Cutout => return None,
53 Role::Hole => Fill::Solid(APERTURE),
54 Role::Pointer => Fill::Solid(if dark { 0x66d6de } else { 0x147888 }),
55 Role::Accent => Fill::Solid(0xd2a34e),
56 Role::Water => Fill::Solid(body(dark)[0]),
57 Role::Tool => Fill::Solid(if dark { 0xfaf8f5 } else { 0x202123 }),
58 Role::Body => Fill::Gradient(body(dark)),
59 })
60 }
61
62 /// Centered stroke width, in logical pixels, for a window `scale`.
63 ///
64 /// The fill covers the inner half of a centered stroke, so the width is
65 /// twice the visible device-pixel count. That count is `round(scale)` and
66 /// never less than one, which is one device pixel at 1× and one logical
67 /// pixel at an integer scale. A non-positive or non-finite scale is 1×.
68 pub fn keyline_stroke(scale: f64) -> f64 {
69 let scale = if scale.is_finite() && scale > 0. {
70 scale
71 } else {
72 1.
73 };
74 2. * scale.round().max(1.) / scale
75 }
76
77 /// Centered stroke width for the light hairline: twice the rim's, so after
78 /// the rim paints over its inner half exactly one more device pixel shows
79 /// outside the dark one.
80 pub fn halo_stroke(scale: f64) -> f64 {
81 2. * keyline_stroke(scale)
82 }
83
84 #[cfg(test)]
85 mod tests {
86 use super::keyline_stroke;
87
88 #[test]
89 fn keyline_stroke_is_one_visible_device_pixel_on_the_grid() {
90 assert_eq!(keyline_stroke(1.), 2.);
91 assert_eq!(keyline_stroke(2.), 2.);
92 assert_eq!(keyline_stroke(3.), 2.);
93 assert!((keyline_stroke(1.25) - 1.6).abs() < 1e-9);
94 for scale in [0.5, 1.0, 1.25, 1.5, 2.0, 2.5, 3.0] {
95 let visible = keyline_stroke(scale) / 2. * scale;
96 let want = scale.round().max(1.);
97 assert!(
98 (visible - want).abs() < 1e-9,
99 "scale {scale}: visible {visible} device px, want {want}"
100 );
101 }
102 assert_eq!(keyline_stroke(0.), keyline_stroke(1.));
103 assert_eq!(keyline_stroke(-2.), keyline_stroke(1.));
104 assert_eq!(keyline_stroke(f64::NAN), keyline_stroke(1.));
105 }
106 }
107
107 lines RUST