Skip to main content

cranpose_ui_graphics/
brush.rs

1//! Brush definitions for painting (solid colors, gradients, etc.)
2
3use crate::{color::Color, geometry::Point, render_effect::TileMode};
4
5#[derive(Clone, Debug, PartialEq)]
6pub enum Brush {
7    Solid(Color),
8    LinearGradient {
9        colors: Vec<Color>,
10        stops: Option<Vec<f32>>,
11        start: Point,
12        end: Point,
13        tile_mode: TileMode,
14    },
15    RadialGradient {
16        colors: Vec<Color>,
17        stops: Option<Vec<f32>>,
18        center: Point,
19        radius: f32,
20        tile_mode: TileMode,
21    },
22    SweepGradient {
23        colors: Vec<Color>,
24        stops: Option<Vec<f32>>,
25        center: Point,
26    },
27}
28
29fn split_color_stops(color_stops: Vec<(f32, Color)>) -> (Vec<Color>, Vec<f32>) {
30    let mut colors = Vec::with_capacity(color_stops.len());
31    let mut stops = Vec::with_capacity(color_stops.len());
32    for (stop, color) in color_stops {
33        colors.push(color);
34        stops.push(stop);
35    }
36    (colors, stops)
37}
38
39/// A colour paints as a solid brush wherever a brush is taken, as Compose
40/// takes a `Color` beside each `Brush` overload.
41impl From<Color> for Brush {
42    fn from(color: Color) -> Self {
43        Brush::Solid(color)
44    }
45}
46
47impl Brush {
48    pub fn solid(color: Color) -> Self {
49        Brush::Solid(color)
50    }
51
52    /// Creates a linear gradient that defaults to Compose semantics:
53    /// start at `(0,0)`, end at `(+inf,+inf)`, and `TileMode::Clamp`.
54    pub fn linear_gradient(colors: Vec<Color>) -> Self {
55        Self::linear_gradient_with_tile_mode(
56            colors,
57            Point { x: 0.0, y: 0.0 },
58            Point {
59                x: f32::INFINITY,
60                y: f32::INFINITY,
61            },
62            TileMode::Clamp,
63        )
64    }
65
66    pub fn linear_gradient_range(colors: Vec<Color>, start: Point, end: Point) -> Self {
67        Self::linear_gradient_with_tile_mode(colors, start, end, TileMode::Clamp)
68    }
69
70    pub fn linear_gradient_with_tile_mode(
71        colors: Vec<Color>,
72        start: Point,
73        end: Point,
74        tile_mode: TileMode,
75    ) -> Self {
76        Brush::LinearGradient {
77            colors,
78            stops: None,
79            start,
80            end,
81            tile_mode,
82        }
83    }
84
85    pub fn linear_gradient_stops(
86        color_stops: Vec<(f32, Color)>,
87        start: Point,
88        end: Point,
89        tile_mode: TileMode,
90    ) -> Self {
91        let (colors, stops) = split_color_stops(color_stops);
92        Brush::LinearGradient {
93            colors,
94            stops: Some(stops),
95            start,
96            end,
97            tile_mode,
98        }
99    }
100
101    pub fn vertical_gradient(colors: Vec<Color>, start_y: f32, end_y: f32) -> Self {
102        Self::vertical_gradient_tiled(colors, start_y, end_y, TileMode::Clamp)
103    }
104
105    pub fn vertical_gradient_tiled(
106        colors: Vec<Color>,
107        start_y: f32,
108        end_y: f32,
109        tile_mode: TileMode,
110    ) -> Self {
111        Self::linear_gradient_with_tile_mode(
112            colors,
113            Point { x: 0.0, y: start_y },
114            Point { x: 0.0, y: end_y },
115            tile_mode,
116        )
117    }
118
119    pub fn vertical_gradient_default(colors: Vec<Color>) -> Self {
120        Self::vertical_gradient_tiled(colors, 0.0, f32::INFINITY, TileMode::Clamp)
121    }
122
123    pub fn vertical_gradient_stops(
124        color_stops: Vec<(f32, Color)>,
125        start_y: f32,
126        end_y: f32,
127        tile_mode: TileMode,
128    ) -> Self {
129        Self::linear_gradient_stops(
130            color_stops,
131            Point { x: 0.0, y: start_y },
132            Point { x: 0.0, y: end_y },
133            tile_mode,
134        )
135    }
136
137    pub fn horizontal_gradient(colors: Vec<Color>, start_x: f32, end_x: f32) -> Self {
138        Self::horizontal_gradient_tiled(colors, start_x, end_x, TileMode::Clamp)
139    }
140
141    pub fn horizontal_gradient_tiled(
142        colors: Vec<Color>,
143        start_x: f32,
144        end_x: f32,
145        tile_mode: TileMode,
146    ) -> Self {
147        Self::linear_gradient_with_tile_mode(
148            colors,
149            Point { x: start_x, y: 0.0 },
150            Point { x: end_x, y: 0.0 },
151            tile_mode,
152        )
153    }
154
155    pub fn horizontal_gradient_default(colors: Vec<Color>) -> Self {
156        Self::horizontal_gradient_tiled(colors, 0.0, f32::INFINITY, TileMode::Clamp)
157    }
158
159    pub fn horizontal_gradient_stops(
160        color_stops: Vec<(f32, Color)>,
161        start_x: f32,
162        end_x: f32,
163        tile_mode: TileMode,
164    ) -> Self {
165        Self::linear_gradient_stops(
166            color_stops,
167            Point { x: start_x, y: 0.0 },
168            Point { x: end_x, y: 0.0 },
169            tile_mode,
170        )
171    }
172
173    pub fn radial_gradient(colors: Vec<Color>, center: Point, radius: f32) -> Self {
174        Self::radial_gradient_tiled(colors, center, radius, TileMode::Clamp)
175    }
176
177    pub fn radial_gradient_tiled(
178        colors: Vec<Color>,
179        center: Point,
180        radius: f32,
181        tile_mode: TileMode,
182    ) -> Self {
183        Brush::RadialGradient {
184            colors,
185            stops: None,
186            center,
187            radius,
188            tile_mode,
189        }
190    }
191
192    pub fn radial_gradient_stops(
193        color_stops: Vec<(f32, Color)>,
194        center: Point,
195        radius: f32,
196        tile_mode: TileMode,
197    ) -> Self {
198        let (colors, stops) = split_color_stops(color_stops);
199        Brush::RadialGradient {
200            colors,
201            stops: Some(stops),
202            center,
203            radius,
204            tile_mode,
205        }
206    }
207
208    pub fn sweep_gradient(colors: Vec<Color>, center: Point) -> Self {
209        Brush::SweepGradient {
210            colors,
211            stops: None,
212            center,
213        }
214    }
215
216    pub fn sweep_gradient_stops(color_stops: Vec<(f32, Color)>, center: Point) -> Self {
217        let (colors, stops) = split_color_stops(color_stops);
218        Brush::SweepGradient {
219            colors,
220            stops: Some(stops),
221            center,
222        }
223    }
224}
225
226#[cfg(test)]
227#[path = "tests/brush_tests.rs"]
228mod tests;