1use crate::color::sRGB;
5use crate::layout::{Layout, leaf};
6use crate::{DAbsPoint, SourceID};
7use std::marker::PhantomData;
8use std::rc::Rc;
9use std::sync::Arc;
10
11#[repr(u8)]
12pub enum ShapeKind {
13 RoundRect,
14 Triangle,
15 Circle,
16 Arc,
17}
18
19pub struct Shape<T, const KIND: u8> {
20 id: std::sync::Arc<SourceID>,
21 props: Rc<T>,
22 border: f32,
23 blur: f32,
24 size: crate::DAbsPoint,
25 corners: [f32; 4],
26 fill: sRGB,
27 outline: sRGB,
28}
29
30pub fn round_rect<T: leaf::Padded + 'static>(
31 id: std::sync::Arc<SourceID>,
32 props: T,
33 border: f32,
34 blur: f32,
35 corners: wide::f32x4,
36 fill: sRGB,
37 outline: sRGB,
38 size: DAbsPoint,
39) -> Shape<T, { ShapeKind::RoundRect as u8 }> {
40 Shape {
41 id,
42 props: props.into(),
43 border,
44 blur,
45 corners: corners.to_array(),
46 fill,
47 outline,
48 size,
49 }
50}
51
52pub fn triangle<T: leaf::Padded + 'static>(
53 id: std::sync::Arc<SourceID>,
54 props: T,
55 border: f32,
56 blur: f32,
57 corners: [f32; 3],
58 offset: f32,
59 fill: sRGB,
60 outline: sRGB,
61 size: DAbsPoint,
62) -> Shape<T, { ShapeKind::Triangle as u8 }> {
63 Shape {
64 id,
65 props: props.into(),
66 border,
67 blur,
68 corners: [corners[0], corners[1], corners[2], offset],
69 fill,
70 outline,
71 size,
72 }
73}
74
75pub fn circle<T: leaf::Padded + 'static>(
76 id: std::sync::Arc<SourceID>,
77 props: T,
78 border: f32,
79 blur: f32,
80 radii: [f32; 2],
81 fill: sRGB,
82 outline: sRGB,
83 size: DAbsPoint,
84) -> Shape<T, { ShapeKind::Circle as u8 }> {
85 Shape {
86 id,
87 props: props.into(),
88 border,
89 blur,
90 corners: [radii[0], radii[1], 0.0, 0.0],
91 fill,
92 outline,
93 size,
94 }
95}
96
97pub fn arcs<T: leaf::Padded + 'static>(
98 id: std::sync::Arc<SourceID>,
99 props: T,
100 border: f32,
101 blur: f32,
102 inner_radius: f32,
103 arcs: [f32; 2],
104 fill: sRGB,
105 outline: sRGB,
106 size: DAbsPoint,
107) -> Shape<T, { ShapeKind::Arc as u8 }> {
108 Shape {
109 id,
110 props: props.into(),
111 border,
112 blur,
113 corners: [arcs[0] + arcs[1] * 0.5, arcs[1] * 0.5, inner_radius, 0.0],
114 fill,
115 outline,
116 size,
117 }
118}
119
120impl<T: leaf::Padded + 'static, const KIND: u8> Clone for Shape<T, KIND> {
121 fn clone(&self) -> Self {
122 Self {
123 id: self.id.duplicate(),
124 props: self.props.clone(),
125 border: self.border,
126 blur: self.blur,
127 corners: self.corners,
128 fill: self.fill,
129 outline: self.outline,
130 size: self.size,
131 }
132 }
133}
134
135impl<T: leaf::Padded + 'static> Shape<T, { ShapeKind::RoundRect as u8 }> {
136 pub fn new(
137 id: std::sync::Arc<SourceID>,
138 props: T,
139 border: f32,
140 blur: f32,
141 corners: wide::f32x4,
142 fill: sRGB,
143 outline: sRGB,
144 size: DAbsPoint,
145 ) -> Self {
146 Self {
147 id,
148 props: props.into(),
149 border,
150 blur,
151 corners: corners.to_array(),
152 fill,
153 outline,
154 size,
155 }
156 }
157}
158
159impl<T: leaf::Padded + 'static> Shape<T, { ShapeKind::Triangle as u8 }> {
160 pub fn new(
161 id: std::sync::Arc<SourceID>,
162 props: T,
163 border: f32,
164 blur: f32,
165 corners: [f32; 3],
166 offset: f32,
167 fill: sRGB,
168 outline: sRGB,
169 size: DAbsPoint,
170 ) -> Self {
171 Self {
172 id,
173 props: props.into(),
174 border,
175 blur,
176 corners: [corners[0], corners[1], corners[2], offset],
177 fill,
178 outline,
179 size,
180 }
181 }
182}
183
184impl<T: leaf::Padded + 'static> Shape<T, { ShapeKind::Circle as u8 }> {
185 pub fn new(
186 id: std::sync::Arc<SourceID>,
187 props: T,
188 border: f32,
189 blur: f32,
190 radii: [f32; 2],
191 fill: sRGB,
192 outline: sRGB,
193 size: DAbsPoint,
194 ) -> Self {
195 Self {
196 id,
197 props: props.into(),
198 border,
199 blur,
200 corners: [radii[0], radii[1], 0.0, 0.0],
201 fill,
202 outline,
203 size,
204 }
205 }
206}
207
208impl<T: leaf::Padded + 'static> Shape<T, { ShapeKind::Arc as u8 }> {
209 pub fn new(
210 id: std::sync::Arc<SourceID>,
211 props: T,
212 border: f32,
213 blur: f32,
214 inner_radius: f32,
215 arcs: [f32; 2],
216 fill: sRGB,
217 outline: sRGB,
218 size: DAbsPoint,
219 ) -> Self {
220 Self {
221 id,
222 props: props.into(),
223 border,
224 blur,
225 corners: [arcs[0] + arcs[1] * 0.5, arcs[1] * 0.5, inner_radius, 0.0],
226 fill,
227 outline,
228 size,
229 }
230 }
231}
232
233impl<T: leaf::Padded + 'static, const KIND: u8> crate::StateMachineChild for Shape<T, KIND> {
234 fn id(&self) -> std::sync::Arc<SourceID> {
235 self.id.clone()
236 }
237}
238
239impl<T: leaf::Padded + 'static, const KIND: u8> super::Component for Shape<T, KIND>
240where
241 for<'a> &'a T: Into<&'a (dyn leaf::Padded + 'static)>,
242{
243 type Props = T;
244
245 fn layout(
246 &self,
247 manager: &mut crate::StateManager,
248 _: &crate::graphics::Driver,
249 window: &Arc<SourceID>,
250 ) -> Box<dyn Layout<T>> {
251 let dpi = manager
252 .get::<super::window::WindowStateMachine>(window)
253 .map(|x| x.state.dpi)
254 .unwrap_or(crate::BASE_DPI);
255
256 let mut corners = self.corners;
257 if KIND == ShapeKind::RoundRect as u8 {
258 corners[0] *= dpi.width;
259 corners[1] *= dpi.height;
260 corners[2] *= dpi.width;
261 corners[3] *= dpi.height;
262 }
263
264 Box::new(leaf::Sized::<T> {
265 props: self.props.clone(),
266 id: Arc::downgrade(&self.id),
267 size: self.size.resolve(dpi).to_vector().to_size().cast_unit(),
268 renderable: Some(Rc::new(crate::render::shape::Instance::<
269 crate::render::shape::Shape<KIND>,
270 > {
271 padding: self.props.padding().as_perimeter(dpi),
272 border: self.border,
273 blur: self.blur,
274 fill: self.fill,
275 outline: self.outline,
276 corners,
277 id: self.id.clone(),
278 phantom: PhantomData,
279 })),
280 })
281 }
282}