astrelis_geometry/
style.rs1use crate::{Fill, Paint, Stroke, Transform2D};
6use astrelis_render::Color;
7
8#[derive(Debug, Clone, PartialEq)]
12pub struct Style {
13 pub fill: Option<Fill>,
15 pub stroke: Option<Stroke>,
17 pub transform: Transform2D,
19}
20
21impl Style {
22 pub fn new() -> Self {
24 Self {
25 fill: None,
26 stroke: None,
27 transform: Transform2D::IDENTITY,
28 }
29 }
30
31 pub fn fill(paint: impl Into<Paint>) -> Self {
33 Self {
34 fill: Some(Fill::from_paint(paint.into())),
35 stroke: None,
36 transform: Transform2D::IDENTITY,
37 }
38 }
39
40 pub fn fill_color(color: Color) -> Self {
42 Self::fill(Paint::solid(color))
43 }
44
45 pub fn stroke(paint: impl Into<Paint>, width: f32) -> Self {
47 Self {
48 fill: None,
49 stroke: Some(Stroke::from_paint(paint.into(), width)),
50 transform: Transform2D::IDENTITY,
51 }
52 }
53
54 pub fn stroke_color(color: Color, width: f32) -> Self {
56 Self::stroke(Paint::solid(color), width)
57 }
58
59 pub fn fill_and_stroke(
61 fill_paint: impl Into<Paint>,
62 stroke_paint: impl Into<Paint>,
63 stroke_width: f32,
64 ) -> Self {
65 Self {
66 fill: Some(Fill::from_paint(fill_paint.into())),
67 stroke: Some(Stroke::from_paint(stroke_paint.into(), stroke_width)),
68 transform: Transform2D::IDENTITY,
69 }
70 }
71
72 pub fn with_fill(mut self, fill: Fill) -> Self {
74 self.fill = Some(fill);
75 self
76 }
77
78 pub fn with_fill_paint(mut self, paint: impl Into<Paint>) -> Self {
80 self.fill = Some(Fill::from_paint(paint.into()));
81 self
82 }
83
84 pub fn with_fill_color(mut self, color: Color) -> Self {
86 self.fill = Some(Fill::solid(color));
87 self
88 }
89
90 pub fn with_stroke(mut self, stroke: Stroke) -> Self {
92 self.stroke = Some(stroke);
93 self
94 }
95
96 pub fn with_stroke_paint(mut self, paint: impl Into<Paint>, width: f32) -> Self {
98 self.stroke = Some(Stroke::from_paint(paint.into(), width));
99 self
100 }
101
102 pub fn with_stroke_color(mut self, color: Color, width: f32) -> Self {
104 self.stroke = Some(Stroke::solid(color, width));
105 self
106 }
107
108 pub fn with_transform(mut self, transform: Transform2D) -> Self {
110 self.transform = transform;
111 self
112 }
113
114 pub fn has_fill(&self) -> bool {
116 self.fill.as_ref().is_some_and(|f| f.opacity > 0.0)
117 }
118
119 pub fn has_stroke(&self) -> bool {
121 self.stroke.as_ref().is_some_and(|s| s.is_visible())
122 }
123
124 pub fn is_visible(&self) -> bool {
126 self.has_fill() || self.has_stroke()
127 }
128
129 pub fn get_fill_color(&self) -> Option<Color> {
131 self.fill.as_ref().and_then(|f| f.effective_color())
132 }
133
134 pub fn get_stroke_color(&self) -> Option<Color> {
136 self.stroke.as_ref().and_then(|s| s.effective_color())
137 }
138}
139
140impl Default for Style {
141 fn default() -> Self {
142 Self::new()
143 }
144}
145
146pub mod presets {
148 use super::*;
149
150 pub fn red_fill() -> Style {
152 Style::fill_color(Color::RED)
153 }
154
155 pub fn green_fill() -> Style {
157 Style::fill_color(Color::GREEN)
158 }
159
160 pub fn blue_fill() -> Style {
162 Style::fill_color(Color::BLUE)
163 }
164
165 pub fn black_stroke() -> Style {
167 Style::stroke_color(Color::BLACK, 1.0)
168 }
169
170 pub fn white_stroke() -> Style {
172 Style::stroke_color(Color::WHITE, 1.0)
173 }
174
175 pub fn outline() -> Style {
177 Style::stroke_color(Color::BLACK, 1.0)
178 }
179
180 pub fn debug() -> Style {
182 Style::fill_and_stroke(Paint::solid(Color::RED), Paint::solid(Color::BLUE), 2.0)
183 }
184}
185
186#[cfg(test)]
187mod tests {
188 use super::*;
189
190 #[test]
191 fn test_empty_style() {
192 let style = Style::new();
193 assert!(!style.is_visible());
194 assert!(!style.has_fill());
195 assert!(!style.has_stroke());
196 }
197
198 #[test]
199 fn test_fill_only() {
200 let style = Style::fill_color(Color::RED);
201 assert!(style.is_visible());
202 assert!(style.has_fill());
203 assert!(!style.has_stroke());
204 }
205
206 #[test]
207 fn test_stroke_only() {
208 let style = Style::stroke_color(Color::BLUE, 2.0);
209 assert!(style.is_visible());
210 assert!(!style.has_fill());
211 assert!(style.has_stroke());
212 }
213
214 #[test]
215 fn test_fill_and_stroke() {
216 let style =
217 Style::fill_and_stroke(Paint::solid(Color::RED), Paint::solid(Color::BLACK), 1.0);
218 assert!(style.has_fill());
219 assert!(style.has_stroke());
220 }
221}