epaint/
shape_transform.rs

1use std::sync::Arc;
2
3use crate::{
4    CircleShape, Color32, ColorMode, CubicBezierShape, EllipseShape, Mesh, PathShape,
5    QuadraticBezierShape, RectShape, Shape, TextShape, color,
6};
7
8/// Remember to handle [`Color32::PLACEHOLDER`] specially!
9pub fn adjust_colors(
10    shape: &mut Shape,
11    adjust_color: impl Fn(&mut Color32) + Send + Sync + Copy + 'static,
12) {
13    #![expect(clippy::match_same_arms)]
14    match shape {
15        Shape::Noop => {}
16
17        Shape::Vec(shapes) => {
18            for shape in shapes {
19                adjust_colors(shape, adjust_color);
20            }
21        }
22
23        Shape::LineSegment { stroke, points: _ } => {
24            adjust_color(&mut stroke.color);
25        }
26
27        Shape::Path(PathShape {
28            points: _,
29            closed: _,
30            fill,
31            stroke,
32        })
33        | Shape::QuadraticBezier(QuadraticBezierShape {
34            points: _,
35            closed: _,
36            fill,
37            stroke,
38        })
39        | Shape::CubicBezier(CubicBezierShape {
40            points: _,
41            closed: _,
42            fill,
43            stroke,
44        }) => {
45            adjust_color(fill);
46            adjust_color_mode(&mut stroke.color, adjust_color);
47        }
48
49        Shape::Circle(CircleShape {
50            center: _,
51            radius: _,
52            fill,
53            stroke,
54        })
55        | Shape::Ellipse(EllipseShape {
56            center: _,
57            radius: _,
58            fill,
59            stroke,
60            angle: _,
61        })
62        | Shape::Rect(RectShape {
63            rect: _,
64            corner_radius: _,
65            fill,
66            stroke,
67            stroke_kind: _,
68            round_to_pixels: _,
69            blur_width: _,
70            brush: _,
71            angle: _,
72        }) => {
73            adjust_color(fill);
74            adjust_color(&mut stroke.color);
75        }
76
77        Shape::Text(TextShape {
78            pos: _,
79            galley,
80            underline,
81            fallback_color,
82            override_text_color,
83            opacity_factor: _,
84            angle: _,
85        }) => {
86            adjust_color(&mut underline.color);
87            adjust_color(fallback_color);
88            if let Some(override_text_color) = override_text_color {
89                adjust_color(override_text_color);
90            }
91
92            if !galley.is_empty() {
93                let galley = Arc::make_mut(galley);
94                for placed_row in &mut galley.rows {
95                    let row = Arc::make_mut(&mut placed_row.row);
96                    for vertex in &mut row.visuals.mesh.vertices {
97                        adjust_color(&mut vertex.color);
98                    }
99                }
100            }
101        }
102
103        Shape::Mesh(mesh) => {
104            let Mesh {
105                indices: _,
106                vertices,
107                texture_id: _,
108            } = Arc::make_mut(mesh);
109
110            for v in vertices {
111                adjust_color(&mut v.color);
112            }
113        }
114
115        Shape::Callback(_) => {
116            // Can't tint user callback code
117        }
118    }
119}
120
121fn adjust_color_mode(
122    color_mode: &mut ColorMode,
123    adjust_color: impl Fn(&mut Color32) + Send + Sync + Copy + 'static,
124) {
125    match color_mode {
126        color::ColorMode::Solid(color) => adjust_color(color),
127        color::ColorMode::UV(callback) => {
128            let callback = Arc::clone(callback);
129            *color_mode = color::ColorMode::UV(Arc::new(Box::new(move |rect, pos| {
130                let mut color = callback(rect, pos);
131                adjust_color(&mut color);
132                color
133            })));
134        }
135    }
136}