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#[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 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 }
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 for handler in &self.app_event_handlers {
197 handler(&e);
198 }
199
200 match e {
201 AppEvent::Show => {
202 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 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 self.render();
226 }
229 _ => {}
230 }
231
232 if self.dirty.get_state() {
233 w.post_redisplay();
234 }
235 });
236 }
237}