circular_layout/
circular_layout.rs1use aetna_core::prelude::*;
18
19fn circular(ctx: LayoutCtx) -> Vec<Rect> {
20 let cx = ctx.container.x + ctx.container.w * 0.5;
21 let cy = ctx.container.y + ctx.container.h * 0.5;
22 let radius = ctx.container.w.min(ctx.container.h) * 0.38;
23 let n = ctx.children.len();
24 if n == 0 {
25 return Vec::new();
26 }
27
28 ctx.children
29 .iter()
30 .enumerate()
31 .map(|(i, child)| {
32 if i == 0 {
34 let (w, h) = (ctx.measure)(child);
35 return Rect::new(cx - w * 0.5, cy - h * 0.5, w, h);
36 }
37 let ring_count = (n - 1) as f32;
38 let theta =
39 (i - 1) as f32 / ring_count * std::f32::consts::TAU - std::f32::consts::FRAC_PI_2;
40 let (w, h) = (ctx.measure)(child);
41 let x = cx + radius * theta.cos() - w * 0.5;
42 let y = cy + radius * theta.sin() - h * 0.5;
43 Rect::new(x, y, w, h)
44 })
45 .collect()
46}
47
48fn fixture() -> El {
49 let centre = h2("Compass").center_text();
50 let dirs = [
51 ("North", "n"),
52 ("NE", "ne"),
53 ("East", "e"),
54 ("SE", "se"),
55 ("South", "s"),
56 ("SW", "sw"),
57 ("West", "w"),
58 ("NW", "nw"),
59 ];
60
61 let mut children: Vec<El> = vec![centre];
62 for (label, k) in dirs {
63 children.push(button(label).key(k).primary());
64 }
65
66 column([
67 h1("Custom layout — circular"),
68 paragraph(
69 "Eight buttons positioned on a circle by an author-supplied \
70 LayoutFn. Stock paint, automatic hover/press, and hit-test \
71 all keep working — only the rect distribution changed.",
72 )
73 .muted(),
74 stack(children)
75 .key("compass")
76 .layout(circular)
77 .width(Size::Fill(1.0))
78 .height(Size::Fixed(360.0)),
79 ])
80 .gap(tokens::SPACE_4)
81 .padding(tokens::SPACE_7)
82}
83
84fn main() -> std::io::Result<()> {
85 let mut root = fixture();
86
87 let viewport = Rect::new(0.0, 0.0, 600.0, 540.0);
88 let bundle = render_bundle(&mut root, viewport);
89
90 let out_dir = std::path::PathBuf::from(env!("CARGO_MANIFEST_DIR")).join("out");
91 let written = write_bundle(&bundle, &out_dir, "circular_layout")?;
92 for p in &written {
93 println!("wrote {}", p.display());
94 }
95
96 if !bundle.lint.findings.is_empty() {
97 eprintln!("\nlint findings ({}):", bundle.lint.findings.len());
98 eprint!("{}", bundle.lint.text());
99 }
100
101 Ok(())
102}