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
39impl Brush {
40    pub fn solid(color: Color) -> Self {
41        Brush::Solid(color)
42    }
43
44    /// Creates a linear gradient that defaults to Compose semantics:
45    /// start at `(0,0)`, end at `(+inf,+inf)`, and `TileMode::Clamp`.
46    pub fn linear_gradient(colors: Vec<Color>) -> Self {
47        Self::linear_gradient_with_tile_mode(
48            colors,
49            Point { x: 0.0, y: 0.0 },
50            Point {
51                x: f32::INFINITY,
52                y: f32::INFINITY,
53            },
54            TileMode::Clamp,
55        )
56    }
57
58    pub fn linear_gradient_range(colors: Vec<Color>, start: Point, end: Point) -> Self {
59        Self::linear_gradient_with_tile_mode(colors, start, end, TileMode::Clamp)
60    }
61
62    pub fn linear_gradient_with_tile_mode(
63        colors: Vec<Color>,
64        start: Point,
65        end: Point,
66        tile_mode: TileMode,
67    ) -> Self {
68        Brush::LinearGradient {
69            colors,
70            stops: None,
71            start,
72            end,
73            tile_mode,
74        }
75    }
76
77    pub fn linear_gradient_stops(
78        color_stops: Vec<(f32, Color)>,
79        start: Point,
80        end: Point,
81        tile_mode: TileMode,
82    ) -> Self {
83        let (colors, stops) = split_color_stops(color_stops);
84        Brush::LinearGradient {
85            colors,
86            stops: Some(stops),
87            start,
88            end,
89            tile_mode,
90        }
91    }
92
93    pub fn vertical_gradient(colors: Vec<Color>, start_y: f32, end_y: f32) -> Self {
94        Self::vertical_gradient_tiled(colors, start_y, end_y, TileMode::Clamp)
95    }
96
97    pub fn vertical_gradient_tiled(
98        colors: Vec<Color>,
99        start_y: f32,
100        end_y: f32,
101        tile_mode: TileMode,
102    ) -> Self {
103        Self::linear_gradient_with_tile_mode(
104            colors,
105            Point { x: 0.0, y: start_y },
106            Point { x: 0.0, y: end_y },
107            tile_mode,
108        )
109    }
110
111    pub fn vertical_gradient_default(colors: Vec<Color>) -> Self {
112        Self::vertical_gradient_tiled(colors, 0.0, f32::INFINITY, TileMode::Clamp)
113    }
114
115    pub fn vertical_gradient_stops(
116        color_stops: Vec<(f32, Color)>,
117        start_y: f32,
118        end_y: f32,
119        tile_mode: TileMode,
120    ) -> Self {
121        Self::linear_gradient_stops(
122            color_stops,
123            Point { x: 0.0, y: start_y },
124            Point { x: 0.0, y: end_y },
125            tile_mode,
126        )
127    }
128
129    pub fn horizontal_gradient(colors: Vec<Color>, start_x: f32, end_x: f32) -> Self {
130        Self::horizontal_gradient_tiled(colors, start_x, end_x, TileMode::Clamp)
131    }
132
133    pub fn horizontal_gradient_tiled(
134        colors: Vec<Color>,
135        start_x: f32,
136        end_x: f32,
137        tile_mode: TileMode,
138    ) -> Self {
139        Self::linear_gradient_with_tile_mode(
140            colors,
141            Point { x: start_x, y: 0.0 },
142            Point { x: end_x, y: 0.0 },
143            tile_mode,
144        )
145    }
146
147    pub fn horizontal_gradient_default(colors: Vec<Color>) -> Self {
148        Self::horizontal_gradient_tiled(colors, 0.0, f32::INFINITY, TileMode::Clamp)
149    }
150
151    pub fn horizontal_gradient_stops(
152        color_stops: Vec<(f32, Color)>,
153        start_x: f32,
154        end_x: f32,
155        tile_mode: TileMode,
156    ) -> Self {
157        Self::linear_gradient_stops(
158            color_stops,
159            Point { x: start_x, y: 0.0 },
160            Point { x: end_x, y: 0.0 },
161            tile_mode,
162        )
163    }
164
165    pub fn radial_gradient(colors: Vec<Color>, center: Point, radius: f32) -> Self {
166        Self::radial_gradient_tiled(colors, center, radius, TileMode::Clamp)
167    }
168
169    pub fn radial_gradient_tiled(
170        colors: Vec<Color>,
171        center: Point,
172        radius: f32,
173        tile_mode: TileMode,
174    ) -> Self {
175        Brush::RadialGradient {
176            colors,
177            stops: None,
178            center,
179            radius,
180            tile_mode,
181        }
182    }
183
184    pub fn radial_gradient_stops(
185        color_stops: Vec<(f32, Color)>,
186        center: Point,
187        radius: f32,
188        tile_mode: TileMode,
189    ) -> Self {
190        let (colors, stops) = split_color_stops(color_stops);
191        Brush::RadialGradient {
192            colors,
193            stops: Some(stops),
194            center,
195            radius,
196            tile_mode,
197        }
198    }
199
200    pub fn sweep_gradient(colors: Vec<Color>, center: Point) -> Self {
201        Brush::SweepGradient {
202            colors,
203            stops: None,
204            center,
205        }
206    }
207
208    pub fn sweep_gradient_stops(color_stops: Vec<(f32, Color)>, center: Point) -> Self {
209        let (colors, stops) = split_color_stops(color_stops);
210        Brush::SweepGradient {
211            colors,
212            stops: Some(stops),
213            center,
214        }
215    }
216}
217
218#[cfg(test)]
219#[path = "tests/brush_tests.rs"]
220mod tests;