appy/core/
mod.rs

1use environmental::environmental;
2use std::any::{Any, TypeId};
3use std::collections::HashMap;
4use std::mem::take;
5use std::rc::Rc;
6use std::time::SystemTime;
7
8use crate::{components::*, glapp::*, types::*, utils::*};
9
10use self::component::*;
11
12use crate::core::element::root_element;
13
14//use std::time::Instant;
15
16#[doc(hidden)]
17pub mod component;
18
19#[doc(hidden)]
20pub mod element;
21
22environmental!(appy_instance: Appy);
23
24#[doc(hidden)]
25pub struct Appy {
26    instances: HashMap<ComponentPath, ComponentInstance>,
27    previous_instances: HashMap<ComponentPath, ComponentInstance>,
28    root: fn() -> Elements,
29    app_context: Option<Rc<AppContext>>,
30    current_hook_index: usize,
31    current_component_path: Option<ComponentPath>,
32    last_render: Option<SystemTime>,
33    pub app_event_handlers: Vec<Rc<dyn Fn(&AppEvent)>>,
34    pub animation_frame_handlers: Vec<Rc<dyn Fn(f32)>>,
35    pub dirty: Trigger,
36    pub contexts: HashMap<TypeId, Vec<Rc<dyn Any>>>,
37}
38
39impl Appy {
40    pub fn with<F, T: 'static>(f: F) -> T
41    where
42        F: FnOnce(&mut Appy) -> T,
43    {
44        appy_instance::with(|appy| f(appy)).unwrap()
45    }
46
47    pub fn use_hook_ref<F, T: 'static>(&mut self, ctor: F) -> HookRef<T>
48    where
49        F: FnOnce() -> T,
50    {
51        let i = self.current_hook_index;
52        let t = self.dirty.create_trigger();
53
54        self.current_hook_index += 1;
55        self.with_current_component_instance(|ci| ci.create_hook_ref(i, ctor, t))
56    }
57
58    pub fn with_current_component_instance<F, T: 'static>(&mut self, f: F) -> T
59    where
60        F: FnOnce(&mut ComponentInstance) -> T,
61    {
62        let p = self.current_component_path.as_ref().unwrap().clone();
63        if !self.instances.contains_key(&p) {
64            let ci = if self.previous_instances.contains_key(&p) {
65                self.previous_instances.remove(&p).unwrap()
66            } else {
67                ComponentInstance::new()
68            };
69
70            self.instances.insert(p.clone(), ci);
71        }
72
73        let ci = self.instances.get_mut(&p).unwrap();
74        f(ci)
75    }
76
77    fn render_fragment(&mut self, fragment: Elements, component_path: ComponentPath) {
78        for (i, element) in fragment.into_iter().enumerate() {
79            let mut this_path = component_path.clone();
80
81            let key = element.get_key();
82            this_path.push(if key.is_some() {
83                ComponentPathComponent::Key(key.unwrap())
84            } else {
85                ComponentPathComponent::Index(i as i32)
86            });
87
88            self.render_component(element, this_path);
89        }
90    }
91
92    fn render_component(&mut self, component: Box<dyn Element>, component_path: ComponentPath) {
93        let mut this_path = component_path;
94        this_path.push(ComponentPathComponent::TypeId(component.type_id()));
95
96        if self.instances.contains_key(&this_path) {
97            self.instances.get_mut(&this_path).unwrap().pre_render();
98        }
99
100        self.current_component_path = Some(this_path.clone());
101        self.current_hook_index = 0;
102        let child_fragment = appy_instance::using(self, || component.render());
103
104        self.current_component_path = None;
105        self.render_fragment(child_fragment, this_path.clone());
106
107        if self.instances.contains_key(&this_path) {
108            let ci = &mut self.instances.get_mut(&this_path).unwrap();
109            if ci.second_render.is_some() {
110                let cb = ci.second_render.take().unwrap();
111                let child_fragment = appy_instance::using(self, || cb());
112
113                self.render_fragment(child_fragment, this_path.clone());
114            }
115
116            let ci = &mut self.instances.get_mut(&this_path).unwrap();
117            if ci.post_render.is_some() {
118                let cb = ci.post_render.take().unwrap();
119                appy_instance::using(self, || {
120                    cb();
121                });
122            }
123        }
124    }
125
126    fn render(&mut self) {
127        self.app_event_handlers = vec![];
128        self.animation_frame_handlers = vec![];
129        self.contexts = HashMap::new();
130        self.dirty.set_state(false);
131
132        self.previous_instances = take(&mut self.instances);
133        self.instances = HashMap::new();
134
135        self.app_context.as_ref().unwrap().begin_frame();
136
137        self.render_component(
138            context_provider()
139                .value(self.app_context.clone().unwrap())
140                .children(vec![blk().children(vec![root_element().root(self.root)])]),
141            vec![],
142        );
143
144        self.previous_instances = HashMap::new();
145
146        if self.animation_frame_handlers.len() > 0 {
147            let now = SystemTime::now();
148            let delta = if self.last_render.is_some() {
149                let duration = now.duration_since(self.last_render.unwrap()).unwrap();
150                duration.as_millis() as f64 / 1000.0
151            } else {
152                0.0
153            };
154
155            //println!("delta: {:?}",delta);
156
157            for handler in &self.animation_frame_handlers {
158                handler(delta as f32);
159            }
160
161            self.last_render = if self.dirty.get_state() {
162                Some(now)
163            } else {
164                None
165            }
166        } else {
167            self.last_render = None
168        }
169
170        self.app_context.as_ref().unwrap().end_frame();
171
172        //println!("instances post render: {}",self.instances.len());
173        //println!("dirty after render: {}",self.dirty.get_state());
174    }
175
176    pub fn new(root: fn() -> Elements) -> Self {
177        Self {
178            root,
179            last_render: None,
180            instances: HashMap::new(),
181            previous_instances: HashMap::new(),
182            app_context: None,
183            app_event_handlers: vec![],
184            animation_frame_handlers: vec![],
185            contexts: HashMap::new(),
186            dirty: Trigger::new(),
187            current_component_path: None,
188            current_hook_index: 0,
189        }
190    }
191
192    pub fn run(mut self, app: App) {
193        app.run(move |w, e| {
194            //log_debug!("app: {:?}",e);
195
196            for handler in &self.app_event_handlers {
197                handler(&e);
198            }
199
200            match e {
201                AppEvent::Show => {
202                    //install_debug_output();
203                    if self.app_context.is_none() {
204                        let size = w.size();
205                        self.app_context = Some(Rc::new(AppContext::new(
206                            size.0,
207                            size.1,
208                            w.pixel_ratio(),
209                            Font::from_data(include_bytes!("./Roboto-Regular.ttf")),
210                        )));
211                    }
212                }
213                AppEvent::Resize { width, height } => {
214                    //println!("size: {}x{}",width,height);
215                    let new_context =
216                        self.app_context
217                            .as_ref()
218                            .unwrap()
219                            .resize(width, height, w.pixel_ratio());
220
221                    self.app_context = Some(Rc::new(new_context));
222                }
223                AppEvent::Render => {
224                    //let start = Instant::now();
225                    self.render();
226                    //let duration = start.elapsed();
227                    //println!("Render time: {:?}", duration);
228                }
229                _ => {}
230            }
231
232            if self.dirty.get_state() {
233                w.post_redisplay();
234            }
235        });
236    }
237}