tawasuyu

tawasuyu/llimphi

Sovereign retained-mode GPU UI framework in Rust (wgpu+vello+taffy+parley), Elm loop, 40+ widgets.

Rust 229TOML 101Markdown 82Shell 24052 Sutichaykuna

⎇ 92dd0e5bfb2ca4456006da99437f4100e156d856 widgets/nodegraph/examples/nodegraph_demo.rs Rust · 197 siq'ikuna · 5.7 KB Ñawpa willay Pi imata llamkarqan ch'uya

feat: llimphi standalone — framework UI soberano extraído del monorepo e65e9cc62 · Sergio ·

1//! Showcase de `llimphi-widget-nodegraph`. Cuatro nodos pre-conectados
2//! representando una cadena de audio (`Source → Filter → Mixer →
3//! Output`) y un `LFO` huérfano para que el usuario lo conecte
4//! arrastrando desde su pin de salida hasta el `mod` del filtro.
5//!
6//! - Arrastrá la title bar de cualquier nodo para moverlo.
7//! - Arrastrá desde un pin de salida (lado derecho) y soltá sobre un
8//!   pin de entrada (lado izquierdo) de otro nodo para conectar.
9//!
10//! Corré con: `cargo run -p llimphi-widget-nodegraph --example
11//! nodegraph_demo --release`.
12
13use llimphi_theme::Theme;
14use llimphi_ui::{App, DragPhase, Handle, View};
15use llimphi_widget_nodegraph::{
16    nodegraph_view, NodeId, NodeSpec, NodegraphMetrics, NodegraphPalette, PinIdx, Wire,
17};
18
19#[derive(Clone)]
20enum Msg {
21    DragNode {
22        id: NodeId,
23        // El demo no diferencia Move/End; lo dejamos en el Msg por si
24        // un caller real quiere persistir layout solo en End.
25        #[allow(dead_code)]
26        phase: DragPhase,
27        dx: f32,
28        dy: f32,
29    },
30    Connect {
31        from_node: NodeId,
32        from_pin: PinIdx,
33        to_node: NodeId,
34        to_pin: PinIdx,
35    },
36}
37
38struct Model {
39    nodes: Vec<NodeSpec>,
40    wires: Vec<Wire>,
41}
42
43const ID_SOURCE: NodeId = 1;
44const ID_FILTER: NodeId = 2;
45const ID_MIXER: NodeId = 3;
46const ID_OUTPUT: NodeId = 4;
47const ID_LFO: NodeId = 5;
48
49struct Showcase;
50
51impl App for Showcase {
52    type Model = Model;
53    type Msg = Msg;
54
55    fn title() -> &'static str {
56        "llimphi · nodegraph showcase (drag títulos, arrastrá pin → pin)"
57    }
58
59    fn initial_size() -> (u32, u32) {
60        (1100, 720)
61    }
62
63    fn init(_: &Handle<Msg>) -> Model {
64        Model {
65            nodes: vec![
66                NodeSpec {
67                    id: ID_SOURCE,
68                    label: "Source".into(),
69                    x: 60.0,
70                    y: 80.0,
71                    inputs: vec![],
72                    outputs: vec!["out".into()],
73                },
74                NodeSpec {
75                    id: ID_FILTER,
76                    label: "Filter".into(),
77                    x: 290.0,
78                    y: 80.0,
79                    inputs: vec!["in".into(), "mod".into()],
80                    outputs: vec!["out".into()],
81                },
82                NodeSpec {
83                    id: ID_MIXER,
84                    label: "Mixer".into(),
85                    x: 520.0,
86                    y: 80.0,
87                    inputs: vec!["a".into(), "b".into()],
88                    outputs: vec!["out".into()],
89                },
90                NodeSpec {
91                    id: ID_OUTPUT,
92                    label: "Output".into(),
93                    x: 750.0,
94                    y: 80.0,
95                    inputs: vec!["in".into()],
96                    outputs: vec![],
97                },
98                NodeSpec {
99                    id: ID_LFO,
100                    label: "LFO".into(),
101                    x: 290.0,
102                    y: 260.0,
103                    inputs: vec![],
104                    outputs: vec!["out".into()],
105                },
106            ],
107            wires: vec![
108                Wire {
109                    from_node: ID_SOURCE,
110                    from_output: 0,
111                    to_node: ID_FILTER,
112                    to_input: 0,
113                },
114                Wire {
115                    from_node: ID_FILTER,
116                    from_output: 0,
117                    to_node: ID_MIXER,
118                    to_input: 0,
119                },
120                Wire {
121                    from_node: ID_MIXER,
122                    from_output: 0,
123                    to_node: ID_OUTPUT,
124                    to_input: 0,
125                },
126            ],
127        }
128    }
129
130    fn update(model: Model, msg: Msg, _: &Handle<Msg>) -> Model {
131        let mut m = model;
132        match msg {
133            Msg::DragNode { id, phase: _, dx, dy } => {
134                if let Some(n) = m.nodes.iter_mut().find(|n| n.id == id) {
135                    n.x += dx;
136                    n.y += dy;
137                    if n.x < 0.0 {
138                        n.x = 0.0;
139                    }
140                    if n.y < 0.0 {
141                        n.y = 0.0;
142                    }
143                }
144            }
145            Msg::Connect {
146                from_node,
147                from_pin,
148                to_node,
149                to_pin,
150            } => {
151                if from_node == to_node {
152                    return m;
153                }
154                let exists = m.wires.iter().any(|w| {
155                    w.from_node == from_node
156                        && w.from_output == from_pin
157                        && w.to_node == to_node
158                        && w.to_input == to_pin
159                });
160                if !exists {
161                    m.wires.push(Wire {
162                        from_node,
163                        from_output: from_pin,
164                        to_node,
165                        to_input: to_pin,
166                    });
167                }
168            }
169        }
170        m
171    }
172
173    fn view(model: &Model) -> View<Msg> {
174        let theme = Theme::dark();
175        let palette = NodegraphPalette::from_theme(&theme);
176        let metrics = NodegraphMetrics::default();
177        nodegraph_view(
178            &model.nodes,
179            &model.wires,
180            &palette,
181            &metrics,
182            |id, phase, dx, dy| Some(Msg::DragNode { id, phase, dx, dy }),
183            |from_node, from_pin, to_node, to_pin| {
184                Some(Msg::Connect {
185                    from_node,
186                    from_pin,
187                    to_node,
188                    to_pin,
189                })
190            },
191        )
192    }
193}
194
195fn main() {
196    llimphi_ui::run::<Showcase>();
197}