nesting_outer_chrome_propagates/
nesting_outer_chrome_propagates.rs1use hephaestus::backend::vello::VelloRenderer;
34use hephaestus::color::{rgb8, Color};
35use hephaestus::composition::{beside, grid, Patch, Slot};
36use hephaestus::layout::Cell;
37use hephaestus::text::{draw_text_in_rect, TextRun, TextStyle};
38use hephaestus::{Affine, Brush, FillRule, Path, PickId, Renderer, SceneBuilder};
39use kurbo::Shape;
40
41fn text_cell(text: &str, size: f32) -> Cell {
42 Cell::measured(TextRun::new(text, &TextStyle::new(size), 96.0))
43}
44
45fn plain_plot(id: &str) -> Patch {
46 Patch::new(id).slot(Slot::Panel, Cell::empty())
47}
48
49fn color_for_region(region: &str) -> Color {
50 match region {
51 "panel" => rgb8(40, 60, 90),
52 "axis_top" => rgb8(200, 100, 130),
53 _ => rgb8(120, 120, 120),
54 }
55}
56
57fn main() {
58 let (w, h) = (1400u32, 400u32);
59 let dpi = 96.0;
60
61 let outer_with_chrome = Patch::new("outer_plain")
64 .slot(
65 Slot::AxisTop,
66 text_cell(
67 "axis_top on the outer SIBLING patch\nspans multiple lines\nto propagate INTO the nested composition",
68 14.0,
69 ),
70 )
71 .slot(Slot::Panel, Cell::empty());
72 let nested = grid(
73 1,
74 3,
75 vec![
76 plain_plot("c1").into(),
77 plain_plot("c2").into(),
78 plain_plot("c3").into(),
79 ],
80 );
81 let composed = beside(outer_with_chrome, nested);
82 let layout = composed.solve(hephaestus::Size::new(w as f64, h as f64), dpi);
83
84 let mut renderer = VelloRenderer::new().expect("vello renderer init");
85 {
86 let scene = renderer.scene();
87 let stroke = hephaestus::stroke::Stroke::new(1.0);
88 let text_brush: Brush = rgb8(20, 20, 30).into();
89
90 for (_id, region, rect) in layout.iter() {
91 if region == "panel" {
92 continue;
93 }
94 let c = color_for_region(region);
95 let tint = Color::new([c.components[0], c.components[1], c.components[2], 0.20]);
96 let path: Path = rect.to_path(0.1);
97 scene.fill(
98 FillRule::NonZero,
99 Affine::IDENTITY,
100 &Brush::Solid(tint),
101 None,
102 &path,
103 PickId::Skip,
104 );
105 scene.stroke(
106 &stroke,
107 Affine::IDENTITY,
108 &Brush::Solid(c),
109 None,
110 &path,
111 PickId::Skip,
112 );
113 }
114 for (_id, region, rect) in layout.iter() {
115 if region != "panel" {
116 continue;
117 }
118 let path: Path = rect.to_path(0.1);
119 scene.fill(
120 FillRule::NonZero,
121 Affine::IDENTITY,
122 &Brush::Solid(color_for_region(region)),
123 None,
124 &path,
125 PickId::Skip,
126 );
127 scene.stroke(
128 &stroke,
129 Affine::IDENTITY,
130 &Brush::Solid(rgb8(255, 255, 255)),
131 None,
132 &path,
133 PickId::Skip,
134 );
135 }
136
137 if let Some(rect) = layout.get("outer_plain", Slot::AxisTop) {
138 let run = TextRun::new(
139 "axis_top on the outer SIBLING patch\nspans multiple lines\nto propagate INTO the nested composition",
140 &TextStyle::new(14.0),
141 96.0,
142 );
143 draw_text_in_rect(scene, &run, rect, &text_brush, PickId::Skip);
144 }
145 }
146
147 let mut pixels = vec![0u8; (w * h * 4) as usize];
148 let bg: Color = rgb8(248, 248, 252);
149 renderer
150 .render_to_buffer(w, h, bg, &mut pixels)
151 .expect("render");
152
153 let path = std::env::current_dir()
154 .unwrap()
155 .join("examples/nesting_outer_chrome_propagates.png");
156 hephaestus::image::write_png(&path, w, h, &pixels).expect("write png");
157 println!("wrote {}", path.display());
158
159 let outer_y = layout.get("outer_plain", Slot::Panel).unwrap();
163 let c1_y = layout.get("c1", Slot::Panel).unwrap();
164 let c2_y = layout.get("c2", Slot::Panel).unwrap();
165 let c3_y = layout.get("c3", Slot::Panel).unwrap();
166 println!(
167 "panel y0: outer_plain={}, c1={}, c2={}, c3={}",
168 outer_y.y0, c1_y.y0, c2_y.y0, c3_y.y0
169 );
170 println!("(all four should be equal — outer chrome propagated INTO the nested composition via back sizers)");
171}