nuit_core/
root.rs

1use std::{cell::RefCell, rc::Rc};
2
3use crate::{Context, Diff, Event, IdPath, IdPathBuf, Node, Storage, Update, View};
4
5/// The central state of a Nuit application.
6pub struct Root<T> {
7    view: RefCell<T>,
8    storage: Rc<Storage>,
9    last_render: RefCell<Node>,
10}
11
12impl<T> Root<T> {
13    pub fn new(view: T) -> Self {
14        Self {
15            view: RefCell::new(view),
16            storage: Rc::new(Storage::new()),
17            last_render: RefCell::new(Node::Empty {}),
18        }
19    }
20
21    pub fn storage(&self) -> &Rc<Storage> {
22        &self.storage
23    }
24}
25
26impl<T> Root<T> where T: View {
27    pub fn render(&self) -> Node {
28        let context = Context::new(self.storage.clone());
29        let new_render = self.storage.with_preapplied_changes(|| {
30            self.view.borrow().render(&context)
31        });
32
33        {
34            let last_render = self.last_render.borrow();
35            let diff = new_render.diff(&last_render);
36
37            for (id_path, _) in &diff.removed {
38                self.view.borrow().fire(&Event::Disappear, id_path, &context);
39            }
40
41            self.storage.apply_changes();
42
43            for (id_path, _) in &diff.added {
44                self.view.borrow().fire(&Event::Appear, id_path, &context);
45            }
46        }
47
48        *self.last_render.borrow_mut() = new_render.clone();
49        new_render
50    }
51
52    pub fn render_json(&self) -> String {
53        let node = self.render();
54        serde_json::to_string(&node).expect("Could not serialize view")
55    }
56
57    pub fn fire_event_json(&self, id_path_json: &str, event_json: &str) {
58        let id_path: IdPathBuf = serde_json::from_str(id_path_json).expect("Could not deserialize id path");
59        let event: Event = serde_json::from_str(event_json).expect("Could not deserialize event");
60        self.fire_event(&id_path, &event);
61    }
62
63    pub fn fire_event(&self, id_path: &IdPath, event: &Event) {
64        self.view.borrow().fire(event, id_path, &Context::new(self.storage.clone()));
65    }
66
67    pub fn set_update_callback(&self, update_callback: impl Fn(&Update) + 'static) {
68        self.storage.set_update_callback(update_callback);
69    }
70}