makepad_render/
cx.rs

1use std::collections::HashMap;
2use std::cell::RefCell;
3
4pub use crate::shadergen::*;
5pub use crate::fonts::*;
6pub use crate::turtle::*;
7pub use crate::cursor::*;
8pub use crate::window::*;
9pub use crate::view::*;
10pub use crate::pass::*;
11pub use crate::texture::*;
12pub use crate::text::*;
13pub use crate::shader::*;
14
15pub use crate::math::*;
16pub use crate::events::*;
17pub use crate::colors::*;
18pub use crate::elements::*; 
19pub use crate::animator::*;
20pub use crate::area::*;
21pub use crate::menu::*;
22pub use crate::styling::*;
23pub use crate::liveclient::*;
24
25#[cfg(all(not(feature = "ipc"), target_os = "linux"))] 
26pub use crate::cx_linux::*;
27#[cfg(all(not(feature = "ipc"), target_os = "linux"))]
28pub use crate::cx_opengl::*;
29
30#[cfg(all(not(feature = "ipc"), target_os = "macos"))]
31pub use crate::cx_macos::*;
32#[cfg(all(not(feature = "ipc"), target_os = "macos"))]
33pub use crate::cx_metal::*;
34#[cfg(all(not(feature = "ipc"), target_os = "macos"))]
35pub use crate::cx_metalsl::*;
36
37#[cfg(all(not(feature = "ipc"), target_os = "windows"))]
38pub use crate::cx_windows::*;
39#[cfg(all(not(feature = "ipc"), target_os = "windows"))]
40pub use crate::cx_dx11::*;
41#[cfg(all(not(feature = "ipc"), target_os = "windows"))]
42pub use crate::cx_hlsl::*;
43
44#[cfg(all(not(feature = "ipc"), target_arch = "wasm32"))]
45pub use crate::cx_webgl::*;
46
47#[cfg(all(not(feature = "ipc"), any(target_arch = "wasm32", target_os = "linux")))]
48pub use crate::cx_glsl::*;
49
50#[cfg(all(not(feature = "ipc"), any(target_os = "linux", target_os = "macos", target_os = "windows")))]
51pub use crate::cx_desktop::*;
52
53#[cfg(all(not(feature = "ipc"), target_arch = "wasm32"))]
54pub use crate::cx_wasm32::*;
55
56#[cfg(feature = "ipc")]
57pub use crate::cx_ipc_child::*;
58
59#[cfg(all(feature = "ipc", target_arch = "wasm32"))]
60pub use crate::cx_ipc_wasm32::*;
61
62#[cfg(all(feature = "ipc", any(target_os = "linux", target_os = "macos")))]
63pub use crate::cx_ipc_posix::*;
64
65#[cfg(all(feature = "ipc", target_os = "windows"))]
66pub use crate::cx_ipc_win32::*;
67
68pub enum PlatformType {
69    Windows,
70    OSX,
71    Linux,
72    WASM
73}
74
75impl PlatformType {
76    pub fn is_desktop(&self) -> bool {
77        match self {
78            PlatformType::Windows => true,
79            PlatformType::OSX => true,
80            PlatformType::Linux => true,
81            PlatformType::WASM => false
82        }
83    }
84}
85
86pub struct Cx {
87    pub running: bool,
88    pub counter: usize,
89    pub platform_type: PlatformType,
90    
91    pub windows: Vec<CxWindow>,
92    pub windows_free: Vec<usize>,
93    pub passes: Vec<CxPass>,
94    pub passes_free: Vec<usize>,
95    pub views: Vec<CxView>,
96    pub views_free: Vec<usize>,
97    
98    pub fonts: Vec<CxFont>,
99    pub fonts_atlas: CxFontsAtlas,
100    pub textures: Vec<CxTexture>,
101    pub textures_free: Vec<usize>,
102    pub shaders: Vec<CxShader>,
103    pub shader_map: HashMap<ShaderGen, usize>,
104    pub shader_instance_id: usize,
105    
106    pub str_to_id: RefCell<HashMap<String, usize>>,
107    pub id_to_str: RefCell<HashMap<usize, String>>,
108    
109    pub is_in_redraw_cycle: bool,
110    pub vr_can_present: bool,
111    pub default_dpi_factor: f32,
112    pub current_dpi_factor: f32,
113    pub window_stack: Vec<usize>,
114    pub pass_stack: Vec<usize>,
115    pub view_stack: Vec<usize>,
116    pub turtles: Vec<Turtle>,
117    pub align_list: Vec<Area>,
118    
119    pub redraw_child_areas: Vec<Area>,
120    pub redraw_parent_areas: Vec<Area>,
121    pub _redraw_child_areas: Vec<Area>,
122    pub _redraw_parent_areas: Vec<Area>,
123    
124    pub redraw_id: u64,
125    pub repaint_id: u64,
126    pub event_id: u64,
127    pub timer_id: u64,
128    pub signal_id: usize,
129    pub theme_update_id: usize,
130    
131    pub prev_key_focus: Area,
132    pub next_key_focus: Area,
133    pub key_focus: Area,
134    pub keys_down: Vec<KeyEvent>,
135    
136    pub debug_area: Area,
137    
138    pub down_mouse_cursor: Option<MouseCursor>,
139    pub hover_mouse_cursor: Option<MouseCursor>,
140    pub captured_fingers: Vec<Area>,
141    pub finger_tap_count: Vec<(Vec2, f64, u32)>,
142    pub finger_down_abs_start: Vec<Vec2>,
143    pub finger_down_rel_start: Vec<Vec2>,
144    pub finger_over_last_area: Area,
145    pub _finger_over_last_area: Area,
146    
147    pub playing_anim_areas: Vec<AnimArea>,
148    pub ended_anim_areas: Vec<AnimArea>,
149    
150    pub frame_callbacks: Vec<Area>,
151    pub _frame_callbacks: Vec<Area>,
152    
153    pub signals: HashMap<Signal, Vec<StatusId>>,
154    
155    pub style_base: CxStyle,
156    pub styles: Vec<CxStyle>,
157    pub style_map: HashMap<StyleId, usize>,
158    pub style_stack: Vec<usize>,
159    
160    pub command_settings: HashMap<CommandId, CxCommandSetting>,
161    
162    pub panic_now: bool,
163    pub panic_redraw: bool,
164    
165    pub live_client: Option<LiveClient>,
166    
167    pub platform: CxPlatform,
168}
169
170#[derive(Clone, Copy, Default)]
171pub struct CxCommandSetting {
172    pub shift: bool,
173    pub key_code: KeyCode,
174    pub enabled: bool
175}
176
177#[derive(Default)]
178pub struct CxStyle {
179    pub colors: HashMap<ColorId, Color>,
180    pub text_styles: HashMap<TextStyleId, TextStyle>,
181    pub layouts: HashMap<LayoutId, Layout>,
182    pub walks: HashMap<WalkId, Walk>,
183    pub anims: HashMap<AnimId, Anim>,
184    pub shaders: HashMap<ShaderId, Shader>,
185    pub floats: HashMap<FloatId, f32>,
186}
187
188pub const NUM_FINGERS: usize = 10;
189
190impl Default for Cx {
191    fn default() -> Self {
192        let mut captured_fingers = Vec::new();
193        let mut finger_tap_count = Vec::new();
194        let mut finger_down_abs_start = Vec::new();
195        let mut finger_down_rel_start = Vec::new();
196        
197        captured_fingers.resize(NUM_FINGERS, Area::Empty);
198        finger_tap_count.resize(NUM_FINGERS, (Vec2::default(), 0.0, 0));
199        finger_down_abs_start.resize(NUM_FINGERS, Vec2::default());
200        finger_down_rel_start.resize(NUM_FINGERS, Vec2::default());
201        
202        let textures = vec![CxTexture {
203            desc: TextureDesc {
204                format: TextureFormat::ImageBGRA,
205                width: Some(4),
206                height: Some(4),
207                multisample: None
208            },
209            image_u32: vec![0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
210            image_f32: Vec::new(),
211            update_image: true,
212            platform: CxPlatformTexture::default()
213        }];
214        
215        Self {
216            counter: 0,
217            platform_type: PlatformType::Windows,
218            running: true,
219            
220            live_client: LiveClient::connect_to_live_server(None),
221            
222            windows: Vec::new(),
223            windows_free: Vec::new(),
224            passes: Vec::new(),
225            passes_free: Vec::new(),
226            views: vec![CxView {..Default::default()}],
227            views_free: Vec::new(),
228            
229            fonts: Vec::new(),
230            fonts_atlas: CxFontsAtlas::default(),
231            textures: textures,
232            textures_free: Vec::new(),
233            shaders: Vec::new(),
234            shader_map: HashMap::new(),
235            id_to_str: RefCell::new(HashMap::new()),
236            str_to_id: RefCell::new(HashMap::new()),
237            
238            default_dpi_factor: 1.0,
239            current_dpi_factor: 1.0,
240            is_in_redraw_cycle: false,
241            vr_can_present: false,
242            window_stack: Vec::new(),
243            pass_stack: Vec::new(),
244            view_stack: Vec::new(),
245            turtles: Vec::new(),
246            align_list: Vec::new(),
247            
248            redraw_parent_areas: Vec::new(),
249            _redraw_parent_areas: Vec::new(),
250            redraw_child_areas: Vec::new(),
251            _redraw_child_areas: Vec::new(),
252            
253            redraw_id: 1,
254            event_id: 1,
255            repaint_id: 1,
256            timer_id: 1,
257            signal_id: 1,
258            shader_instance_id: 1,
259            theme_update_id: 1,
260            
261            next_key_focus: Area::Empty,
262            prev_key_focus: Area::Empty,
263            key_focus: Area::Empty,
264            keys_down: Vec::new(),
265            
266            debug_area: Area::Empty,
267            
268            down_mouse_cursor: None,
269            hover_mouse_cursor: None,
270            captured_fingers: captured_fingers,
271            finger_tap_count: finger_tap_count,
272            finger_down_abs_start: finger_down_abs_start,
273            finger_down_rel_start: finger_down_rel_start,
274            finger_over_last_area: Area::Empty,
275            _finger_over_last_area: Area::Empty,
276            
277            style_base: CxStyle::default(),
278            styles: Vec::new(),
279            style_map: HashMap::new(),
280            style_stack: Vec::new(),
281            
282            command_settings: HashMap::new(),
283            
284            playing_anim_areas: Vec::new(),
285            ended_anim_areas: Vec::new(),
286            
287            frame_callbacks: Vec::new(),
288            _frame_callbacks: Vec::new(),
289            
290            signals: HashMap::new(),
291            
292            panic_now: false,
293            panic_redraw: false,
294            
295            platform: CxPlatform {..Default::default()},
296        }
297    }
298}
299
300
301impl Cx {
302    
303    pub fn add_shader(&mut self, sg: ShaderGen, name: &str) -> Shader {
304        let inst_id = self.shader_instance_id;
305        self.shader_instance_id += 1;
306        if let Some(stored_id) = self.shader_map.get(&sg) {
307            return Shader {shader_id: Some((*stored_id, inst_id))}
308        }
309        
310        let new_id = self.shaders.len();
311        self.shader_map.insert(sg.clone(), new_id);
312        self.shaders.push(CxShader {
313            name: name.to_string(),
314            shader_gen: sg,
315            platform: None,
316            mapping: CxShaderMapping::default()
317        });
318        Shader {shader_id: Some((new_id, inst_id))}
319    }
320    
321    pub fn process_tap_count(&mut self, digit: usize, pos: Vec2, time: f64) -> u32 {
322        if digit >= self.finger_tap_count.len() {
323            return 0
324        };
325        let (last_pos, last_time, count) = self.finger_tap_count[digit];
326        
327        if (time - last_time) < 0.5 && pos.distance(&last_pos) < 10. {
328            self.finger_tap_count[digit] = (pos, time, count + 1);
329            count + 1
330        }
331        else {
332            self.finger_tap_count[digit] = (pos, time, 1);
333            1
334        }
335    }
336    
337    pub fn get_dpi_factor_of(&mut self, area: &Area) -> f32 {
338        match area {
339            Area::Instance(ia) => {
340                let pass_id = self.views[ia.view_id].pass_id;
341                return self.get_delegated_dpi_factor(pass_id)
342            },
343            Area::View(va) => {
344                let pass_id = self.views[va.view_id].pass_id;
345                return self.get_delegated_dpi_factor(pass_id)
346            },
347            _ => ()
348        }
349        return 1.0;
350    }
351    
352    pub fn get_delegated_dpi_factor(&mut self, pass_id: usize) -> f32 {
353        let mut dpi_factor = 1.0;
354        let mut pass_id_walk = pass_id;
355        for _ in 0..25 {
356            match self.passes[pass_id_walk].dep_of {
357                CxPassDepOf::Window(window_id) => {
358                    dpi_factor = match self.windows[window_id].window_state {
359                        CxWindowState::Create {..} => {
360                            self.default_dpi_factor
361                        },
362                        CxWindowState::Created => {
363                            self.windows[window_id].window_geom.dpi_factor
364                        },
365                        _ => 1.0
366                    };
367                    break;
368                },
369                CxPassDepOf::Pass(next_pass_id) => {
370                    pass_id_walk = next_pass_id;
371                },
372                _ => {break;}
373            }
374        }
375        dpi_factor
376    }
377    
378    pub fn compute_passes_to_repaint(&mut self, passes_todo: &mut Vec<usize>, windows_need_repaint: &mut usize) {
379        passes_todo.truncate(0);
380        
381        for (pass_id, cxpass) in self.passes.iter().enumerate() {
382            if cxpass.paint_dirty {
383                let mut inserted = false;
384                match cxpass.dep_of {
385                    CxPassDepOf::Window(_) => {
386                        *windows_need_repaint += 1
387                    },
388                    CxPassDepOf::Pass(dep_of_pass_id) => {
389                        for insert_before in 0..passes_todo.len() {
390                            if passes_todo[insert_before] == dep_of_pass_id {
391                                passes_todo.insert(insert_before, pass_id);
392                                inserted = true;
393                                break;
394                            }
395                        }
396                    },
397                    CxPassDepOf::None => { // we need to be first
398                        passes_todo.insert(0, pass_id);
399                        inserted = true;
400                    },
401                }
402                if !inserted {
403                    passes_todo.push(pass_id);
404                }
405            }
406        }
407    }
408    
409    pub fn redraw_pass_of(&mut self, area: Area) {
410        // we walk up the stack of area
411        match area {
412            Area::All => {
413                for window_id in 0..self.windows.len() {
414                    let redraw = match self.windows[window_id].window_state {
415                        CxWindowState::Create {..} | CxWindowState::Created => {
416                            true
417                        },
418                        _ => false
419                    };
420                    if redraw {
421                        if let Some(pass_id) = self.windows[window_id].main_pass_id {
422                            self.redraw_pass_and_dep_of_passes(pass_id);
423                        }
424                    }
425                }
426            },
427            Area::Empty => (),
428            Area::Instance(instance) => {
429                self.redraw_pass_and_dep_of_passes(self.views[instance.view_id].pass_id);
430            },
431            Area::View(viewarea) => {
432                self.redraw_pass_and_dep_of_passes(self.views[viewarea.view_id].pass_id);
433            }
434        }
435    }
436    
437    pub fn redraw_pass_and_dep_of_passes(&mut self, pass_id: usize) {
438        let mut walk_pass_id = pass_id;
439        loop {
440            if let Some(main_view_id) = self.passes[walk_pass_id].main_view_id {
441                self.redraw_parent_area(Area::View(ViewArea {redraw_id: 0, view_id: main_view_id}));
442            }
443            match self.passes[walk_pass_id].dep_of.clone() {
444                CxPassDepOf::Pass(next_pass_id) => {
445                    walk_pass_id = next_pass_id;
446                },
447                _ => {
448                    break;
449                }
450            }
451        }
452    }
453    
454    pub fn redraw_pass_and_sub_passes(&mut self, pass_id: usize) {
455        let cxpass = &self.passes[pass_id];
456        if let Some(main_view_id) = cxpass.main_view_id {
457            self.redraw_parent_area(Area::View(ViewArea {redraw_id: 0, view_id: main_view_id}));
458        }
459        // lets redraw all subpasses as well
460        for sub_pass_id in 0..self.passes.len() {
461            if let CxPassDepOf::Pass(dep_pass_id) = self.passes[sub_pass_id].dep_of.clone() {
462                if dep_pass_id == pass_id {
463                    self.redraw_pass_and_sub_passes(sub_pass_id);
464                }
465            }
466        }
467    }
468    
469    pub fn redraw_child_area(&mut self, area: Area) {
470        if self.panic_redraw {
471            #[cfg(debug_assertions)]
472            panic!("Panic Redraw triggered")
473        }
474        
475        // if we are redrawing all, clear the rest
476        if area == Area::All {
477            self.redraw_child_areas.truncate(0);
478        }
479        // check if we are already redrawing all
480        else if self.redraw_child_areas.len() == 1 && self.redraw_child_areas[0] == Area::All {
481            return;
482        };
483        // only add it if we dont have it already
484        if let Some(_) = self.redraw_child_areas.iter().position( | a | *a == area) {
485            return;
486        }
487        self.redraw_child_areas.push(area);
488    }
489    
490    pub fn redraw_parent_area(&mut self, area: Area) {
491        if self.panic_redraw {
492            #[cfg(debug_assertions)]
493            panic!("Panic Redraw triggered")
494        }
495        
496        // if we are redrawing all, clear the rest
497        if area == Area::All {
498            self.redraw_parent_areas.truncate(0);
499        }
500        // check if we are already redrawing all
501        else if self.redraw_parent_areas.len() == 1 && self.redraw_parent_areas[0] == Area::All {
502            return;
503        };
504        // only add it if we dont have it already
505        if let Some(_) = self.redraw_parent_areas.iter().position( | a | *a == area) {
506            return;
507        }
508        self.redraw_parent_areas.push(area);
509    }
510    
511    pub fn redraw_previous_areas(&mut self) {
512        for area in self._redraw_child_areas.clone() {
513            self.redraw_child_area(area);
514        }
515        for area in self._redraw_parent_areas.clone() {
516            self.redraw_parent_area(area);
517        }
518    }
519    
520    pub fn view_will_redraw(&self, view_id: usize) -> bool {
521        
522        // figure out if areas are in some way a child of draw_list_id, then we need to redraw
523        for area in &self._redraw_child_areas {
524            match area {
525                Area::All => {
526                    return true;
527                },
528                Area::Empty => (),
529                Area::Instance(instance) => {
530                    let mut vw = instance.view_id;
531                    if vw == view_id {
532                        return true
533                    }
534                    while vw != 0 {
535                        vw = self.views[vw].nesting_view_id;
536                        if vw == view_id {
537                            return true
538                        }
539                    }
540                },
541                Area::View(viewarea) => {
542                    let mut vw = viewarea.view_id;
543                    if vw == view_id {
544                        return true
545                    }
546                    while vw != 0 {
547                        vw = self.views[vw].nesting_view_id;
548                        if vw == view_id {
549                            return true
550                        }
551                    }
552                }
553            }
554        }
555        // figure out if areas are in some way a parent of draw_list_id, then redraw
556        for area in &self._redraw_parent_areas {
557            match area {
558                Area::All => {
559                    return true;
560                },
561                Area::Empty => (),
562                Area::Instance(instance) => {
563                    let mut vw = view_id;
564                    if vw == instance.view_id {
565                        return true
566                    }
567                    while vw != 0 {
568                        vw = self.views[vw].nesting_view_id;
569                        if vw == instance.view_id {
570                            return true
571                        }
572                    }
573                },
574                Area::View(viewarea) => {
575                    let mut vw = view_id;
576                    if vw == viewarea.view_id {
577                        return true
578                    }
579                    while vw != 0 {
580                        vw = self.views[vw].nesting_view_id;
581                        if vw == viewarea.view_id {
582                            return true
583                        }
584                    }
585                    
586                }
587            }
588        }
589        
590        false
591    }
592    
593    pub fn check_ended_anim_areas(&mut self, time: f64) {
594        let mut i = 0;
595        self.ended_anim_areas.truncate(0);
596        loop {
597            if i >= self.playing_anim_areas.len() {
598                break
599            }
600            let anim_start_time = self.playing_anim_areas[i].start_time;
601            let anim_total_time = self.playing_anim_areas[i].total_time;
602            if anim_start_time.is_nan() || time - anim_start_time >= anim_total_time {
603                self.ended_anim_areas.push(self.playing_anim_areas.remove(i));
604            }
605            else {
606                i = i + 1;
607            }
608        }
609    }
610    
611    pub fn update_area_refs(&mut self, old_area: Area, new_area: Area) {
612        if old_area == Area::Empty || old_area == Area::All {
613            return
614        }
615        
616        if let Some(anim_anim) = self.playing_anim_areas.iter_mut().find( | v | v.area == old_area) {
617            anim_anim.area = new_area.clone()
618        }
619        
620        if let Some(digit_area) = self.captured_fingers.iter_mut().find( | v | **v == old_area) {
621            *digit_area = new_area.clone()
622        }
623        // update capture keyboard
624        if self.key_focus == old_area {
625            self.key_focus = new_area.clone()
626        }
627        
628        // update capture keyboard
629        if self.prev_key_focus == old_area {
630            self.prev_key_focus = new_area.clone()
631        }
632        if self.next_key_focus == old_area {
633            self.next_key_focus = new_area.clone()
634        }        
635        if self._finger_over_last_area == old_area {
636            self._finger_over_last_area = new_area.clone()
637        }
638        //
639        if let Some(next_frame) = self.frame_callbacks.iter_mut().find( | v | **v == old_area) {
640            *next_frame = new_area.clone()
641        }
642    }
643    
644    pub fn set_key_focus(&mut self, focus_area: Area) {
645        self.next_key_focus = focus_area;
646    }
647
648    pub fn revert_key_focus(&mut self) {
649        self.next_key_focus = self.prev_key_focus;
650    }
651    
652    pub fn has_key_focus(&self, focus_area: Area) -> bool {
653        self.key_focus == focus_area
654    }
655    
656    pub fn process_key_down(&mut self, key_event: KeyEvent) {
657        if let Some(_) = self.keys_down.iter().position( | k | k.key_code == key_event.key_code) {
658            return;
659        }
660        self.keys_down.push(key_event);
661    }
662    
663    pub fn process_key_up(&mut self, key_event: &KeyEvent) {
664        for i in 0..self.keys_down.len() {
665            if self.keys_down[i].key_code == key_event.key_code {
666                self.keys_down.remove(i);
667                return
668            }
669        }
670    }
671    
672    pub fn call_all_keys_up<F>(&mut self, mut event_handler: F)
673    where F: FnMut(&mut Cx, &mut Event)
674    {
675        let mut keys_down = Vec::new();
676        std::mem::swap(&mut keys_down, &mut self.keys_down);
677        for key_event in keys_down {
678            self.call_event_handler(&mut event_handler, &mut Event::KeyUp(key_event))
679        }
680    }
681    
682    // event handler wrappers
683    
684    pub fn call_event_handler<F>(&mut self, mut event_handler: F, event: &mut Event)
685    where F: FnMut(&mut Cx, &mut Event)
686    {
687        self.event_id += 1;
688        event_handler(self, event);
689        
690        if self.next_key_focus != self.key_focus {
691            self.prev_key_focus = self.key_focus;
692            self.key_focus = self.next_key_focus;
693            event_handler(self, &mut Event::KeyFocus(KeyFocusEvent {
694                prev: self.prev_key_focus,
695                focus: self.key_focus
696            }))
697        }
698    }
699    
700    pub fn call_draw_event<F>(&mut self, mut event_handler: F)
701    where F: FnMut(&mut Cx, &mut Event)
702    {
703        // self.profile();
704        self.is_in_redraw_cycle = true;
705        self.redraw_id += 1;
706        self.counter = 0;
707        std::mem::swap(&mut self._redraw_child_areas, &mut self.redraw_child_areas);
708        std::mem::swap(&mut self._redraw_parent_areas, &mut self.redraw_parent_areas);
709        self.align_list.truncate(0);
710        self.redraw_child_areas.truncate(0);
711        self.redraw_parent_areas.truncate(0);
712        self.call_event_handler(&mut event_handler, &mut Event::Draw);
713        self.is_in_redraw_cycle = false;
714        if self.style_stack.len()>0{
715            panic!("Style stack disaligned, forgot a cx.end_style()");
716        }
717        if self.view_stack.len()>0{
718            panic!("View stack disaligned, forgot an end_view(cx)");
719        }
720        if self.pass_stack.len()>0{
721            panic!("Pass stack disaligned, forgot an end_pass(cx)");
722        }
723        if self.window_stack.len()>0{
724            panic!("Window stack disaligned, forgot an end_window(cx)");
725        }
726        if self.turtles.len()>0{
727            panic!("Turtle stack disaligned, forgot an end_turtle()");
728        }
729        //self.profile();
730    }
731    
732    pub fn call_animation_event<F>(&mut self, mut event_handler: F, time: f64)
733    where F: FnMut(&mut Cx, &mut Event)
734    {
735        self.call_event_handler(&mut event_handler, &mut Event::Animate(AnimateEvent {time: time, frame: self.repaint_id}));
736        self.check_ended_anim_areas(time);
737        if self.ended_anim_areas.len() > 0 {
738            self.call_event_handler(&mut event_handler, &mut Event::AnimEnded(AnimateEvent {time: time, frame: self.repaint_id}));
739        }
740    }
741    
742    pub fn call_frame_event<F>(&mut self, mut event_handler: F, time: f64)
743    where F: FnMut(&mut Cx, &mut Event)
744    {
745        std::mem::swap(&mut self._frame_callbacks, &mut self.frame_callbacks);
746        self.frame_callbacks.truncate(0);
747        self.call_event_handler(&mut event_handler, &mut Event::Frame(FrameEvent {time: time, frame: self.repaint_id}));
748    }
749    
750    pub fn next_frame(&mut self, area: Area) {
751        if let Some(_) = self.frame_callbacks.iter().position( | a | *a == area) {
752            return;
753        }
754        self.frame_callbacks.push(area);
755    }
756    
757    pub fn new_signal(&mut self) -> Signal {
758        self.signal_id += 1;
759        return Signal {signal_id: self.signal_id}
760    }
761    
762    pub fn send_signal(&mut self, signal: Signal, status: StatusId) {
763        if signal.signal_id == 0{
764            return
765        }
766        if let Some(statusses) = self.signals.get_mut(&signal){
767            if statusses.iter().find(|s| **s == status).is_none(){
768                statusses.push(status);
769            }
770        }
771        else{
772            self.signals.insert(signal, vec![status]);
773        }
774    }
775    
776    pub fn call_signals<F>(&mut self, mut event_handler: F)
777    where F: FnMut(&mut Cx, &mut Event)
778    {
779        let mut counter = 0;
780        while self.signals.len() != 0 {
781            counter += 1;
782            let mut signals = HashMap::new();
783            std::mem::swap(&mut self.signals, &mut signals);
784            
785            self.call_event_handler(&mut event_handler, &mut Event::Signal(SignalEvent {
786                signals: signals,
787            }));
788
789            if counter > 100 {
790                println!("Signal feedback loop detected");
791                break
792            }
793        }
794    }
795    
796    pub fn status_http_send_ok() -> StatusId {uid!()}
797    pub fn status_http_send_fail() -> StatusId {uid!()}
798    
799    /*
800    pub fn debug_draw_tree_recur(&mut self, draw_list_id: usize, depth:usize){
801        if draw_list_id >= self.draw_lists.len(){
802            println!("---------- Drawlist still empty ---------");
803            return
804        }
805        let mut indent = String::new();
806        for _i in 0..depth{
807            indent.push_str("  ");
808        }
809        let draw_calls_len = self.draw_lists[draw_list_id].draw_calls_len;
810        if draw_list_id == 0{
811            println!("---------- Begin Debug draw tree for redraw_id: {} ---------", self.redraw_id)
812        }
813        println!("{}list {}: len:{} rect:{:?}", indent, draw_list_id, draw_calls_len, self.draw_lists[draw_list_id].rect);
814        indent.push_str("  ");
815        for draw_call_id in 0..draw_calls_len{
816            let sub_list_id = self.draw_lists[draw_list_id].draw_calls[draw_call_id].sub_list_id;
817            if sub_list_id != 0{
818                self.debug_draw_tree_recur(sub_list_id, depth + 1);
819            }
820            else{
821                let draw_list = &mut self.draw_lists[draw_list_id];
822                let draw_call = &mut draw_list.draw_calls[draw_call_id];
823                let sh = &self.shaders[draw_call.shader_id];
824                let shc = &self.compiled_shaders[draw_call.shader_id];
825                let slots = shc.instance_slots;
826                let instances = draw_call.instance.len() / slots;
827                println!("{}call {}: {}({}) x:{}", indent, draw_call_id, sh.name, draw_call.shader_id, instances);
828                // lets dump the instance geometry
829                for inst in 0..instances.min(1){
830                    let mut out = String::new();
831                    let mut off = 0;
832                    for prop in &shc.named_instance_props.props{
833                        match prop.slots{
834                            1=>out.push_str(&format!("{}:{} ", prop.name,
835                                draw_call.instance[inst*slots + off])),
836                            2=>out.push_str(&format!("{}:v2({},{}) ", prop.name,
837                                draw_call.instance[inst*slots+ off],
838                                draw_call.instance[inst*slots+1+ off])),
839                            3=>out.push_str(&format!("{}:v3({},{},{}) ", prop.name,
840                                draw_call.instance[inst*slots+ off],
841                                draw_call.instance[inst*slots+1+ off],
842                                draw_call.instance[inst*slots+1+ off])),
843                            4=>out.push_str(&format!("{}:v4({},{},{},{}) ", prop.name,
844                                draw_call.instance[inst*slots+ off],
845                                draw_call.instance[inst*slots+1+ off],
846                                draw_call.instance[inst*slots+2+ off],
847                                draw_call.instance[inst*slots+3+ off])),
848                            _=>{}
849                        }
850                        off += prop.slots;
851                    }
852                    println!("  {}instance {}: {}", indent, inst, out);
853                }
854            }
855        }
856        if draw_list_id == 0{
857            println!("---------- End Debug draw tree for redraw_id: {} ---------", self.redraw_id)
858        }
859    }*/
860}
861
862// palette types
863
864
865#[derive(Clone)]
866pub enum StyleValue {
867    Color(Color),
868    Font(String),
869    Size(f64)
870}
871
872#[macro_export]
873macro_rules!log {
874    ( $ ( $ arg: tt) *) => ({
875        $ crate::Cx::write_log(&format!("[{}:{}:{}] {}\n", file!(), line!(), column!(), &format!( $ ( $ arg) *)))
876    })
877}
878
879#[macro_export]
880macro_rules!main_app {
881    ( $ app: ident) => {
882        //TODO do this with a macro to generate both entrypoints for App and Cx
883        pub fn main() {
884            let mut cx = Cx::default();
885            let mut app = $ app::new(&mut cx);
886            let mut cxafterdraw = CxAfterDraw::new(&mut cx);
887            cx.event_loop( | cx, mut event | {
888                if let Event::Draw = event {
889                    app.draw_app(cx);
890                    cxafterdraw.after_draw(cx);
891                    return
892                }
893                app.handle_app(cx, &mut event);
894            });
895        }
896        
897        #[export_name = "create_wasm_app"]
898        pub extern "C" fn create_wasm_app() -> u32 {
899            let mut cx = Box::new(Cx::default());
900            let app = Box::new( $ app::new(&mut cx));
901            let cxafterdraw = Box::new(CxAfterDraw::new(&mut cx));
902            Box::into_raw(Box::new((Box::into_raw(app), Box::into_raw(cx), Box::into_raw(cxafterdraw)))) as u32
903        }
904        
905        #[export_name = "process_to_wasm"]
906        pub unsafe extern "C" fn process_to_wasm(appcx: u32, msg_bytes: u32) -> u32 {
907            let appcx = &*(appcx as *mut (*mut $ app, *mut Cx, *mut CxAfterDraw));
908            (*appcx.1).process_to_wasm(msg_bytes, | cx, mut event | {
909                if let Event::Draw = event {
910                    (*appcx.0).draw_app(cx);
911                    (*appcx.2).after_draw(cx);
912                    return;
913                };
914                (*appcx.0).handle_app(cx, &mut event);
915            })
916        }
917    };
918}