1use crate::{AnyPiece, Boundary, BuildCx, Flex, Layout, LayoutOps, Piece, RNode};
6use day_spec::{Proposal, Rect, Size, kinds};
7use std::rc::Rc;
8
9const SHEET_SCRIM: day_spec::Color = day_spec::Color::rgba(0.0, 0.0, 0.0, 0.32);
11const SHEET_RADIUS: f64 = 12.0;
13
14pub struct ComposedSheet {
18 pub content: AnyPiece,
19}
20
21impl Piece for ComposedSheet {
22 fn build(self, cx: &mut BuildCx) -> RNode {
23 let fill = Flex {
24 grow_w: true,
25 grow_h: true,
26 ..Default::default()
27 };
28 let node = cx.native(
29 kinds::CONTAINER,
30 &day_spec::props::ContainerProps::default(),
31 Rc::new(SheetLayout),
32 fill,
33 Boundary::Yes,
34 );
35 cx.under(node, |cx| {
36 cx.native(
37 kinds::CONTAINER,
38 &day_spec::props::ContainerProps {
39 background: Some(SHEET_SCRIM),
40 role: Some(day_spec::SurfaceRole::Scrim),
41 ..Default::default()
42 },
43 Rc::new(FillLayout),
44 fill,
45 Boundary::No,
46 );
47 let card = cx.native(
48 kinds::CONTAINER,
49 &day_spec::props::ContainerProps {
50 background: None,
51 corner_radius: SHEET_RADIUS,
52 clips: true,
53 role: Some(day_spec::SurfaceRole::Window),
54 },
55 Rc::new(FillLayout),
56 fill,
57 Boundary::Yes,
58 );
59 cx.under(card, |cx| {
60 let _ = self.content.build(cx);
61 });
62 });
63 node
64 }
65}
66
67fn sheet_card_size(area: Size) -> Size {
70 Size::new(
71 (area.width - 40.0).clamp(320.0, 640.0).min(area.width),
72 (area.height - 80.0).clamp(300.0, 620.0).min(area.height),
73 )
74}
75
76struct SheetLayout;
78
79impl Layout for SheetLayout {
80 fn measure(&self, _cx: &mut dyn LayoutOps, _children: &[RNode], p: Proposal) -> Size {
81 Size::new(p.width.unwrap_or(0.0), p.height.unwrap_or(0.0))
82 }
83 fn place(&self, cx: &mut dyn LayoutOps, children: &[RNode], bounds: Rect) {
84 let area = bounds.size;
85 if let Some(&scrim) = children.first() {
86 cx.place_child(scrim, Rect::from_size(area));
87 }
88 if let Some(&card) = children.get(1) {
89 let size = sheet_card_size(area);
90 cx.place_child(
91 card,
92 Rect::new(
93 ((area.width - size.width) / 2.0).floor(),
94 ((area.height - size.height) / 2.0).floor(),
95 size.width,
96 size.height,
97 ),
98 );
99 }
100 }
101}
102
103struct FillLayout;
105
106impl Layout for FillLayout {
107 fn measure(&self, _cx: &mut dyn LayoutOps, _children: &[RNode], p: Proposal) -> Size {
108 Size::new(p.width.unwrap_or(0.0), p.height.unwrap_or(0.0))
109 }
110 fn place(&self, cx: &mut dyn LayoutOps, children: &[RNode], bounds: Rect) {
111 for &child in children {
112 cx.place_child(child, Rect::from_size(bounds.size));
113 }
114 }
115}