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