sim-lib-view-daw 0.1.1

DAW timeline, mixer, plugin rack, and synth lenses for the SIM Web-UI (WEBUI_4).
Documentation
//! Shared builders for instrument-specific editor scenes.

use sim_kernel::Expr;
use sim_lib_music_synth::InstrumentEditorDescriptor;
use sim_lib_scene::{data_map, node, sym};

pub(crate) fn editor_root(
    descriptor: &InstrumentEditorDescriptor,
    role: &str,
    fixture_name: &str,
    children: Vec<Expr>,
) -> Expr {
    node(
        "stack",
        vec![
            ("lens", sym(descriptor.view_id)),
            ("role", sym(role)),
            ("route", sym(descriptor.route_name)),
            ("fixture", Expr::String(fixture_name.to_owned())),
            ("fixture-names", string_list(descriptor.fixture_names)),
            ("dir", sym("column")),
            ("children", Expr::List(children)),
        ],
    )
}

pub(crate) fn action(role: &str, action: &str, label: &str) -> Expr {
    node(
        "button",
        vec![
            ("role", sym(role)),
            ("action", sym(action)),
            ("label", Expr::String(label.to_owned())),
        ],
    )
}

pub(crate) fn slider(role: &str, param: &str, min: f64, max: f64, value: f64) -> Expr {
    node(
        "slider",
        vec![
            ("role", sym(role)),
            ("param", sym(param)),
            ("min", number(min)),
            ("max", number(max)),
            ("value", number(value)),
        ],
    )
}

pub(crate) fn table(role: &str, rows: Vec<Expr>) -> Expr {
    node(
        "table",
        vec![("role", sym(role)), ("rows", Expr::List(rows))],
    )
}

pub(crate) fn grid(
    role: &str,
    rows: &[Vec<f64>],
    row_labels: &[&str],
    col_labels: &[&str],
) -> Expr {
    node(
        "grid",
        vec![
            ("role", sym(role)),
            ("rows", numeric_rows(rows)),
            ("row-labels", string_list(row_labels)),
            ("col-labels", string_list(col_labels)),
        ],
    )
}

pub(crate) fn graph(role: &str, nodes: &[&str], edges: &[(&str, &str)]) -> Expr {
    node(
        "graph",
        vec![
            ("role", sym(role)),
            (
                "nodes",
                Expr::List(nodes.iter().map(|name| graph_node(name)).collect()),
            ),
            (
                "edges",
                Expr::List(
                    edges
                        .iter()
                        .map(|(from, to)| graph_edge(from, to))
                        .collect(),
                ),
            ),
        ],
    )
}

pub(crate) fn row(fields: Vec<(&str, Expr)>) -> Expr {
    data_map(fields)
}

pub(crate) fn validation_panel(code: &str, target: &str) -> Expr {
    node(
        "badge",
        vec![
            ("role", sym("instrument-editor-validation")),
            ("status", sym("error")),
            ("validation", sym(code)),
            ("target", sym(target)),
            ("label", Expr::String(format!("{target}: {code}"))),
        ],
    )
}

pub(crate) fn number_list(values: &[f64]) -> Expr {
    Expr::List(values.iter().map(|value| number(*value)).collect())
}

pub(crate) fn string_list(values: &[&str]) -> Expr {
    Expr::List(
        values
            .iter()
            .map(|value| Expr::String((*value).to_owned()))
            .collect(),
    )
}

pub(crate) fn numeric_rows(rows: &[Vec<f64>]) -> Expr {
    Expr::List(
        rows.iter()
            .map(|row| Expr::List(row.iter().map(|value| number(*value)).collect()))
            .collect(),
    )
}

pub(crate) use sim_value::build::float as number;

fn graph_node(name: &str) -> Expr {
    node(
        "node",
        vec![("id", sym(name)), ("label", Expr::String(name.to_owned()))],
    )
}

fn graph_edge(from: &str, to: &str) -> Expr {
    node("edge", vec![("from", sym(from)), ("to", sym(to))])
}