1pub mod base;
5pub mod domain_write;
6pub mod fixed;
7pub mod flex;
8pub mod grid;
9pub mod leaf;
10pub mod list;
11pub mod root;
12pub mod text;
13
14use dyn_clone::DynClone;
15use guillotiere::euclid::{Point2D, Vector2D};
16use wide::f32x4;
17
18use crate::color::sRGB32;
19use crate::render::Renderable;
20use crate::render::compositor::CompositorView;
21use crate::{
22 Error, PxDim, PxLimits, PxPoint, PxRect, RelLimits, SourceID, UNSIZED_AXIS, URect, rtree,
23};
24use derive_where::derive_where;
25use std::marker::PhantomData;
26use std::rc::{Rc, Weak};
27use std::sync::Arc;
28
29pub trait Layout<Props: ?Sized>: DynClone {
34 fn get_props(&self) -> &Props;
35 fn stage<'a>(
36 &self,
37 area: PxRect,
38 limits: PxLimits,
39 window: &mut crate::component::window::WindowState,
40 ) -> Box<dyn Staged + 'a>;
41}
42
43dyn_clone::clone_trait_object!(<Imposed> Layout<Imposed> where Imposed:?Sized);
44
45impl<U: ?Sized, T> Layout<U> for Box<dyn Layout<T>>
46where
47 for<'a> &'a T: Into<&'a U>,
48{
49 fn get_props(&self) -> &U {
50 use std::ops::Deref;
51 Box::deref(self).get_props().into()
52 }
53
54 fn stage<'a>(
55 &self,
56 area: PxRect,
57 limits: PxLimits,
58 window: &mut crate::component::window::WindowState,
59 ) -> Box<dyn Staged + 'a> {
60 use std::ops::Deref;
61 Box::deref(self).stage(area, limits, window)
62 }
63}
64
65impl<U: ?Sized, T> Layout<U> for &dyn Layout<T>
66where
67 for<'a> &'a T: Into<&'a U>,
68{
69 fn get_props(&self) -> &U {
70 (*self).get_props().into()
71 }
72
73 fn stage<'a>(
74 &self,
75 area: PxRect,
76 limits: PxLimits,
77 window: &mut crate::component::window::WindowState,
78 ) -> Box<dyn Staged + 'a> {
79 (*self).stage(area, limits, window)
80 }
81}
82
83pub trait Desc {
84 type Props: ?Sized;
85 type Child: ?Sized;
86 type Children: Clone;
87
88 fn stage<'a>(
90 props: &Self::Props,
91 outer_area: PxRect,
92 limits: PxLimits,
93 children: &Self::Children,
94 id: std::sync::Weak<SourceID>,
95 renderable: Option<Rc<dyn Renderable>>,
96 window: &mut crate::component::window::WindowState,
97 ) -> Box<dyn Staged + 'a>;
98}
99
100#[derive_where(Clone)]
109pub struct Node<T, D: Desc + ?Sized> {
110 pub props: Rc<T>,
111 pub id: std::sync::Weak<SourceID>,
112 pub children: D::Children,
113 pub renderable: Option<Rc<dyn Renderable>>,
114 pub layer: Option<(sRGB32, f32)>,
115}
116
117impl<T, D: Desc + ?Sized> Layout<T> for Node<T, D>
118where
119 for<'a> &'a T: Into<&'a D::Props>,
120{
121 fn get_props(&self) -> &T {
122 self.props.as_ref()
123 }
124 fn stage<'a>(
125 &self,
126 area: PxRect,
127 limits: PxLimits,
128 window: &mut crate::component::window::WindowState,
129 ) -> Box<dyn Staged + 'a> {
130 let mut staged = D::stage(
131 self.props.as_ref().into(),
132 area,
133 limits,
134 &self.children,
135 self.id.clone(),
136 self.renderable.as_ref().map(|x| x.clone()),
137 window,
138 );
139 if let Some((color, rotation)) = self.layer {
140 window.driver.shared.create_layer(
141 &window.driver.device,
142 self.id.upgrade().unwrap(),
143 staged.get_area().to_untyped(),
144 None,
145 color,
146 rotation,
147 false,
148 );
149 staged.set_layer(self.id.clone());
150 }
151 staged
152 }
153}
154
155pub trait Staged: DynClone {
156 fn render(
157 &self,
158 parent_pos: PxPoint,
159 driver: &crate::graphics::Driver,
160 compositor: &mut CompositorView<'_>,
161 dependents: &mut Vec<std::sync::Weak<SourceID>>,
162 ) -> Result<(), Error>;
163 fn get_rtree(&self) -> Weak<rtree::Node>;
164 fn get_area(&self) -> PxRect;
165 fn set_layer(&mut self, _id: std::sync::Weak<SourceID>) {
166 panic!("This staged object doesn't support layers!");
167 }
168}
169
170dyn_clone::clone_trait_object!(Staged);
171
172#[derive(Clone)]
173pub(crate) struct Concrete {
174 renderable: Option<Rc<dyn Renderable>>,
175 area: PxRect,
176 rtree: Rc<rtree::Node>,
177 children: im::Vector<Option<Box<dyn Staged>>>,
178 layer: Option<std::sync::Weak<SourceID>>,
179}
180
181impl Concrete {
182 pub fn new(
183 renderable: Option<Rc<dyn Renderable>>,
184 area: PxRect,
185 rtree: Rc<rtree::Node>,
186 children: im::Vector<Option<Box<dyn Staged>>>,
187 ) -> Self {
188 let (unsized_x, unsized_y) = check_unsized_abs(area.bottomright());
189 assert!(
190 !unsized_x && !unsized_y,
191 "concrete area must always be sized!: {area:?}",
192 );
193 Self {
194 renderable,
195 area,
196 rtree,
197 children,
198 layer: None,
199 }
200 }
201
202 fn render_self(
203 &self,
204 parent_pos: PxPoint,
205 driver: &crate::graphics::Driver,
206 compositor: &mut CompositorView<'_>,
207 ) -> Result<(), Error> {
208 if let Some(r) = &self.renderable {
209 r.render((self.area + parent_pos).to_untyped(), driver, compositor)?;
210 }
211 Ok(())
212 }
213
214 fn render_children(
215 &self,
216 parent_pos: PxPoint,
217 driver: &crate::graphics::Driver,
218 compositor: &mut CompositorView<'_>,
219 dependents: &mut Vec<std::sync::Weak<SourceID>>,
220 ) -> Result<(), Error> {
221 for child in (&self.children).into_iter().flatten() {
222 child.render(
224 parent_pos + self.area.topleft().to_vector(),
225 driver,
226 compositor,
227 dependents,
228 )?;
229 }
230 Ok(())
231 }
232}
233
234impl Staged for Concrete {
235 fn render(
236 &self,
237 parent_pos: PxPoint,
238 driver: &crate::graphics::Driver,
239 compositor: &mut CompositorView<'_>,
240 dependents: &mut Vec<std::sync::Weak<SourceID>>,
241 ) -> Result<(), Error> {
242 if let Some(id) = self.layer.as_ref().and_then(|x| x.upgrade()) {
243 let layers = driver.shared.access_layers();
244 let layer = layers.get(&id).expect("Missing layer in render call!");
245 let mut deps = Vec::new();
246 let mut region_uv = None;
247
248 let (mut view, depview) = if layer.target.is_some() {
249 dependents.push(Arc::downgrade(&id));
251
252 let index = match compositor.index {
255 0 => 1,
256 1 => 2,
257 2 => 1,
258 _ => panic!("Invalid index!"),
259 };
260
261 let mut atlas = driver.layer_atlas[index - 1].write();
262 let region = atlas.cache_region(
263 &driver.device,
264 &id,
265 layer.area.dim().ceil().to_i32(),
266 None,
267 )?;
268 region_uv = Some(region.uv);
269
270 driver.layer_atlas[index % 2].write().remove_cache(&id);
272 assert!(compositor.pass < 0b111111);
273
274 let mut v = CompositorView {
275 index: index as u8,
276 window: compositor.window,
277 layer0: compositor.layer0,
278 layer1: compositor.layer1,
279 clipstack: compositor.clipstack,
280 offset: region.uv.min.to_f32() - layer.area.topleft() - parent_pos.to_vector(),
281 surface_dim: compositor.surface_dim,
282 pass: compositor.pass + 1,
283 slice: region.index,
284 };
285
286 v.reserve(driver);
287 (v, &mut deps)
289 } else {
290 (
293 CompositorView {
294 index: compositor.index,
295 window: compositor.window,
296 layer0: compositor.layer0,
297 layer1: compositor.layer1,
298 clipstack: compositor.clipstack,
299 offset: compositor.offset,
300 surface_dim: compositor.surface_dim,
301 pass: compositor.pass,
302 slice: compositor.slice,
303 },
304 dependents,
305 )
306 };
307
308 view.with_clip(layer.area + parent_pos, |refview| {
310 self.render_self(parent_pos, driver, refview)?;
311 self.render_children(parent_pos, driver, refview, depview)
312 })?;
313
314 if let Some(target) = layer.target.as_ref() {
315 target.write().dependents = deps;
318 compositor.append_layer(layer, parent_pos, region_uv.unwrap());
319 }
320 } else {
321 self.render_self(parent_pos, driver, compositor)?;
322 self.render_children(parent_pos, driver, compositor, dependents)?;
323 };
324
325 Ok(())
326 }
327
328 fn get_rtree(&self) -> Weak<rtree::Node> {
329 Rc::downgrade(&self.rtree)
330 }
331
332 fn get_area(&self) -> PxRect {
333 self.area
334 }
335
336 fn set_layer(&mut self, id: std::sync::Weak<SourceID>) {
337 self.layer = Some(id)
338 }
339}
340
341#[must_use]
342#[inline]
343pub(crate) fn map_unsized_area(mut area: URect, adjust: PxDim) -> URect {
344 let (unsized_x, unsized_y) = check_unsized(area);
345 let abs = area.abs.v.as_array_mut();
346 let rel = area.rel.v.as_array_mut();
347 if unsized_x {
349 rel[2] = rel[0];
350 abs[2] += abs[0] + adjust.width;
352 }
353 if unsized_y {
354 rel[3] = rel[1];
355 abs[3] += abs[1] + adjust.height;
356 }
357 area
358}
359
360#[must_use]
361#[inline]
362pub(crate) fn nuetralize_unsized(v: PxRect) -> PxRect {
363 let (unsized_x, unsized_y) = check_unsized_abs(v.bottomright());
364 let ltrb = v.v.to_array();
365 PxRect {
366 v: f32x4::new([
367 ltrb[0],
368 ltrb[1],
369 if unsized_x { ltrb[0] } else { ltrb[2] },
370 if unsized_y { ltrb[1] } else { ltrb[3] },
371 ]),
372 _unit: PhantomData,
373 }
374}
375
376#[must_use]
377#[inline]
378pub(crate) fn limit_area(mut v: PxRect, limits: PxLimits) -> PxRect {
379 v.set_bottomright(
382 v.bottomright()
383 .max(v.topleft() + limits.min())
384 .min(v.topleft() + limits.max()),
385 );
386 v
387}
388
389#[must_use]
390#[inline]
391pub(crate) fn limit_dim(v: PxDim, limits: PxLimits) -> PxDim {
392 let (unsized_x, unsized_y) = check_unsized_dim(v);
393 PxDim::new(
394 if unsized_x {
395 v.width
396 } else {
397 v.width.max(limits.min().width).min(limits.max().width)
398 },
399 if unsized_y {
400 v.height
401 } else {
402 v.height.max(limits.min().height).min(limits.max().height)
403 },
404 )
405}
406
407#[must_use]
408#[inline]
409pub(crate) fn eval_dim(area: URect, dim: PxDim) -> PxDim {
410 let (unsized_x, unsized_y) = check_unsized(area);
411 PxDim::new(
412 if unsized_x {
413 area.bottomright().rel().x
414 } else {
415 let top = area.topleft().abs().x + (area.topleft().rel().x * dim.width);
416 let bottom = area.bottomright().abs().x + (area.bottomright().rel().x * dim.width);
417 bottom - top
418 },
419 if unsized_y {
420 area.bottomright().rel().y
421 } else {
422 let top = area.topleft().abs().y + (area.topleft().rel().y * dim.height);
423 let bottom = area.bottomright().abs().y + (area.bottomright().rel().y * dim.height);
424 bottom - top
425 },
426 )
427}
428
429#[must_use]
430#[inline]
431pub(crate) fn apply_limit(dim: PxDim, limits: PxLimits, rlimits: RelLimits) -> PxLimits {
432 let (unsized_x, unsized_y) = check_unsized_dim(dim);
433 let sign = limits.v.sign_bit() | rlimits.v.sign_bit();
434 PxLimits {
435 v: (f32x4::new([
436 if unsized_x {
437 limits.min().width
438 } else {
439 limits.min().width.max(dim.width)
440 },
441 if unsized_y {
442 limits.min().height
443 } else {
444 limits.min().height.max(dim.height)
445 },
446 if unsized_x {
447 limits.max().width
448 } else {
449 limits.max().width.min(dim.width)
450 },
451 if unsized_y {
452 limits.max().height
453 } else {
454 limits.max().height.min(dim.height)
455 },
456 ]) * rlimits.v)
457 .copysign(sign),
458 _unit: PhantomData,
459 }
460}
461
462#[must_use]
464#[inline]
465pub(crate) fn check_unsized(area: URect) -> (bool, bool) {
466 (
467 area.bottomright().rel().x == UNSIZED_AXIS,
468 area.bottomright().rel().y == UNSIZED_AXIS,
469 )
470}
471
472#[must_use]
474#[inline]
475pub(crate) fn check_unsized_abs<U>(bottomright: Point2D<f32, U>) -> (bool, bool) {
476 (bottomright.x == UNSIZED_AXIS, bottomright.y == UNSIZED_AXIS)
477}
478
479#[must_use]
481#[inline]
482pub(crate) fn check_unsized_dim(dim: PxDim) -> (bool, bool) {
483 check_unsized_abs(dim.to_vector().to_point())
484}
485
486pub(crate) fn assert_sized(area: PxRect) {
487 let ltrb = area.v.as_array_ref();
488
489 for v in ltrb {
490 assert_ne!(*v, UNSIZED_AXIS);
491 assert!(v.is_finite());
492 }
493}
494
495#[must_use]
496#[inline]
497pub(crate) fn cap_unsized(area: PxRect) -> PxRect {
498 let ltrb = area.v.to_array();
499 PxRect {
500 v: f32x4::new(ltrb.map(|x| {
501 if x.is_finite() {
502 x
503 } else {
504 crate::UNSIZED_AXIS
505 }
506 })),
507 _unit: PhantomData,
508 }
509}
510
511#[must_use]
512#[inline]
513pub(crate) fn apply_anchor(area: PxRect, outer_area: PxRect, mut anchor: PxPoint) -> PxRect {
514 let (unsized_outer_x, unsized_outer_y) = check_unsized_abs(outer_area.bottomright());
515 if unsized_outer_x {
516 anchor.x = 0.0;
517 }
518 if unsized_outer_y {
519 anchor.y = 0.0;
520 }
521 area - anchor
522}
523
524#[must_use]
525#[inline]
526fn swap_pair<T>(xaxis: bool, v: (T, T)) -> (T, T) {
527 if xaxis { (v.0, v.1) } else { (v.1, v.0) }
528}
529
530trait Swappable<T> {
531 fn swap_axis(self, xaxis: bool) -> (T, T);
532}
533
534impl<T, U> Swappable<T> for Point2D<T, U> {
535 #[inline]
536 fn swap_axis(self, xaxis: bool) -> (T, T) {
537 swap_pair(xaxis, (self.x, self.y))
538 }
539}
540
541impl<T, U> Swappable<T> for guillotiere::euclid::Size2D<T, U> {
542 #[inline]
543 fn swap_axis(self, xaxis: bool) -> (T, T) {
544 swap_pair(xaxis, (self.width, self.height))
545 }
546}
547
548impl<T, U> Swappable<T> for Vector2D<T, U> {
549 #[inline]
550 fn swap_axis(self, xaxis: bool) -> (T, T) {
551 swap_pair(xaxis, (self.x, self.y))
552 }
553}
554
555#[must_use]
557#[inline]
558fn merge_margin(prev: f32, margin: f32) -> f32 {
559 if prev.is_nan() { 0.0 } else { margin.max(prev) }
560}