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 => { 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 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 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 area == Area::All {
477 self.redraw_child_areas.truncate(0);
478 }
479 else if self.redraw_child_areas.len() == 1 && self.redraw_child_areas[0] == Area::All {
481 return;
482 };
483 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 area == Area::All {
498 self.redraw_parent_areas.truncate(0);
499 }
500 else if self.redraw_parent_areas.len() == 1 && self.redraw_parent_areas[0] == Area::All {
502 return;
503 };
504 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 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 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 if self.key_focus == old_area {
625 self.key_focus = new_area.clone()
626 }
627
628 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 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 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.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 }
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 }
861
862#[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 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}