rosace_widgets/tree/
scaffold.rs1use rosace_core::types::{Point, Rect, Size};
2use rosace_layout::Constraints;
3use rosace_render::Color;
4use super::{Widget, LayoutCtx, PaintCtx, BoxedWidget, avail_w, avail_h};
5
6pub struct Scaffold {
11 pub background: Color,
12 pub app_bar: Option<BoxedWidget>,
13 pub nav_rail: Option<BoxedWidget>,
14 pub body: BoxedWidget,
15 pub fab: Option<BoxedWidget>,
16 pub bottom_bar: Option<BoxedWidget>,
17 pub sidebar_right: Option<BoxedWidget>,
18}
19
20impl Scaffold {
21 pub fn new(body: impl Widget + 'static) -> Self {
22 Self {
23 background: Color::rgba(0, 0, 0, 0), app_bar: None,
25 nav_rail: None,
26 body: Box::new(body),
27 fab: None,
28 bottom_bar: None,
29 sidebar_right: None,
30 }
31 }
32
33 pub fn background(mut self, c: Color) -> Self { self.background = c; self }
34 pub fn app_bar(mut self, w: impl Widget + 'static) -> Self { self.app_bar = Some(Box::new(w)); self }
35 pub fn nav_rail(mut self, w: impl Widget + 'static) -> Self { self.nav_rail = Some(Box::new(w)); self }
36 pub fn fab(mut self, w: impl Widget + 'static) -> Self { self.fab = Some(Box::new(w)); self }
37 pub fn bottom_bar(mut self, w: impl Widget + 'static) -> Self { self.bottom_bar = Some(Box::new(w)); self }
38 pub fn sidebar_right(mut self, w: impl Widget + 'static) -> Self { self.sidebar_right = Some(Box::new(w)); self }
39}
40
41impl Widget for Scaffold {
42 fn layout(&self, ctx: &LayoutCtx) -> Size {
43 let constraints = ctx.constraints;
44 Size { width: avail_w(constraints), height: avail_h(constraints) }
45 }
46
47 fn paint(&self, ctx: &mut PaintCtx) {
48 let full = ctx.rect;
49
50 let bg = if self.background.a == 0 {
55 ctx.tc(ctx.theme.colors.background)
56 } else {
57 self.background
58 };
59 ctx.fill_rect(full, bg);
60
61 let sa = rosace_core::use_safe_area();
66 let total = Rect {
67 origin: Point { x: full.origin.x + sa.left, y: full.origin.y + sa.top },
68 size: Size {
69 width: (full.size.width - sa.left - sa.right).max(0.0),
70 height: (full.size.height - sa.top - sa.bottom).max(0.0),
71 },
72 };
73
74 let bar_h = self.app_bar.as_ref()
76 .map(|w| w.layout(&ctx.layout_ctx(Constraints::tight(total.size.width, 44.0))).height)
77 .unwrap_or(0.0);
78
79 let bottom_h = self.bottom_bar.as_ref()
81 .map(|w| w.layout(&ctx.layout_ctx(Constraints::tight(total.size.width, 48.0))).height)
82 .unwrap_or(0.0);
83
84 if let Some(bar) = &self.app_bar {
86 bar.paint(&mut ctx.child(Rect {
87 origin: total.origin,
88 size: Size { width: total.size.width, height: bar_h },
89 }));
90 }
91
92 let content_y = total.origin.y + bar_h;
94 let content_h = total.size.height - bar_h - bottom_h;
95
96 let rail_w = self.nav_rail.as_ref()
98 .map(|w| w.layout(&ctx.layout_ctx(Constraints::loose(300.0, content_h))).width)
99 .unwrap_or(0.0);
100
101 if let Some(rail) = &self.nav_rail {
103 rail.paint(&mut ctx.child(Rect {
104 origin: Point { x: total.origin.x, y: content_y },
105 size: Size { width: rail_w, height: content_h },
106 }));
107 }
108
109 let rsb_w = self.sidebar_right.as_ref()
111 .map(|w| w.layout(&ctx.layout_ctx(Constraints::loose(400.0, content_h))).width)
112 .unwrap_or(0.0);
113
114 if let Some(rsb) = &self.sidebar_right {
116 rsb.paint(&mut ctx.child(Rect {
117 origin: Point { x: total.origin.x + total.size.width - rsb_w, y: content_y },
118 size: Size { width: rsb_w, height: content_h },
119 }));
120 }
121
122 let body_x = total.origin.x + rail_w;
124 let body_w = total.size.width - rail_w - rsb_w;
125 self.body.paint(&mut ctx.child(Rect {
126 origin: Point { x: body_x, y: content_y },
127 size: Size { width: body_w, height: content_h },
128 }));
129
130 if let Some(bb) = &self.bottom_bar {
132 super::set_bottom_overlay_inset(bottom_h);
133 bb.paint(&mut ctx.child(Rect {
134 origin: Point { x: total.origin.x, y: total.origin.y + total.size.height - bottom_h },
135 size: Size { width: total.size.width, height: bottom_h },
136 }));
137 }
138
139 if let Some(fab) = &self.fab {
141 let fab_size = fab.layout(&ctx.layout_ctx(Constraints::loose(60.0, 60.0)));
142 let fab_x = total.origin.x + total.size.width - fab_size.width - 20.0;
143 let fab_y = total.origin.y + total.size.height - bottom_h - fab_size.height - 20.0;
144 fab.paint(&mut ctx.child(Rect {
145 origin: Point { x: fab_x, y: fab_y },
146 size: fab_size,
147 }));
148 }
149 }
150}