Skip to main content

sim_lib_web_layout/
scene.rs

1//! Rendering the workspace value to a layout Scene.
2//!
3//! The layout engine emits a Scene describing the dock/split arrangement of
4//! panes. It is pure data built from baseline scene node kinds, so the browser
5//! paints it like any other Scene and the layout is testable headlessly.
6
7use sim_kernel::{Expr, Symbol};
8use sim_lib_scene::{node, sym};
9
10use crate::pane::{pane_dock, pane_id, pane_lens};
11use crate::value::{focus, mode, panes};
12
13/// Encode the workspace value into a layout Scene.
14pub fn workspace_scene(workspace: &Expr) -> Expr {
15    let focused = focus(workspace);
16    let children = panes(workspace)
17        .iter()
18        .map(|pane| pane_box(pane, focused.as_ref()))
19        .collect();
20    node(
21        "stack",
22        vec![
23            ("role", sym("workspace")),
24            ("dir", sym("row")),
25            (
26                "mode",
27                mode(workspace).map(Expr::Symbol).unwrap_or(Expr::Nil),
28            ),
29            ("children", Expr::List(children)),
30        ],
31    )
32}
33
34fn pane_box(pane: &Expr, focused: Option<&Symbol>) -> Expr {
35    let id = pane_id(pane).unwrap_or_else(|| Symbol::new("?"));
36    let dock = pane_dock(pane).unwrap_or_else(|| Symbol::new("center"));
37    let lens = pane_lens(pane).unwrap_or_else(|| Symbol::new("view:default"));
38    let is_focused = focused == Some(&id);
39    node(
40        "box",
41        vec![
42            ("role", sym("pane")),
43            ("id", Expr::Symbol(id.clone())),
44            ("focused", Expr::Bool(is_focused)),
45            (
46                "children",
47                Expr::List(vec![
48                    node("text", vec![("text", Expr::String(format!("pane {id}")))]),
49                    node(
50                        "badge",
51                        vec![
52                            ("status", Expr::Symbol(dock.clone())),
53                            ("label", Expr::String(dock.name.to_string())),
54                        ],
55                    ),
56                    node(
57                        "text",
58                        vec![("text", Expr::String(format!("lens: {lens}")))],
59                    ),
60                ]),
61            ),
62        ],
63    )
64}