makepad_platform/
cx_api.rs

1use {
2    std::{
3        any::{TypeId, Any},
4        rc::Rc,
5    },
6    crate::{
7        makepad_futures::executor::Spawner,
8        makepad_live_id::*,
9        makepad_math::{DVec2, Rect},
10        gpu_info::GpuInfo,
11        cx::{Cx, CxRef, OsType, XrCapabilities},
12        event::{
13            DragItem, 
14            Timer,
15            Trigger,
16            NextFrame,
17            HttpRequest,
18        },
19        draw_list::DrawListId,
20        window::WindowId,
21        cursor::MouseCursor,
22        area::{
23            Area, 
24            //DrawListArea
25        },
26        texture::Texture,
27        macos_menu::MacosMenu,
28        pass::{
29            PassId,
30            CxPassRect,
31            CxPassParent
32        },
33    }
34};
35
36
37pub trait CxOsApi {
38    fn init_cx_os(&mut self);
39    
40    fn spawn_thread<F>(&mut self, f: F) where F: FnOnce() + Send + 'static;
41    
42    fn start_stdin_service(&mut self){}
43    fn pre_start()->bool{false}
44    /*
45    fn web_socket_open(&mut self, url: String, rec: WebSocketAutoReconnect) -> WebSocket;
46    fn web_socket_send(&mut self, socket: WebSocket, data: Vec<u8>);*/
47}
48
49#[derive(PartialEq)]
50pub enum CxOsOp {
51    CreateWindow(WindowId),
52    CloseWindow(WindowId),
53    MinimizeWindow(WindowId),
54    MaximizeWindow(WindowId),
55    FullscreenWindow(WindowId),
56    NormalizeWindow(WindowId),
57    RestoreWindow(WindowId),
58    SetTopmost(WindowId, bool),
59    
60    XrStartPresenting,
61    XrStopPresenting,
62    
63    ShowTextIME(Area, DVec2),
64    HideTextIME,
65    SetCursor(MouseCursor),
66    StartTimer {timer_id: u64, interval: f64, repeats: bool},
67    StopTimer(u64),
68    Quit,
69    
70    StartDragging(Vec<DragItem>),
71    UpdateMacosMenu(MacosMenu),
72    ShowClipboardActions(String),
73
74    HttpRequest{request_id: LiveId, request:HttpRequest},
75
76    WebSocketOpen{request_id: LiveId, request:HttpRequest},
77    WebSocketSendString{request_id: LiveId, data:String},
78    WebSocketSendBinary{request_id: LiveId, data:Vec<u8>},
79
80    InitializeVideoDecoding(LiveId, Rc<Vec<u8>>, usize),
81    DecodeNextVideoChunk(LiveId, usize),
82    FetchNextVideoFrames(LiveId, usize),
83    CleanupVideoDecoding(LiveId),
84}
85
86impl Cx { 
87    pub fn xr_capabilities(&self) -> &XrCapabilities {
88        &self.xr_capabilities 
89    } 
90    
91    pub fn get_ref(&self)->CxRef{
92        CxRef(self.self_ref.clone().unwrap())
93    }
94    
95    pub fn get_dependency(&self, path: &str) -> Result<Rc<Vec<u8>>,
96    String> { 
97        if let Some(data) = self.dependencies.get(path) {
98            if let Some(data) = &data.data {
99                return match data {
100                    Ok(data) => Ok(data.clone()),
101                    Err(s) => Err(s.clone())
102                }
103            } 
104        }
105        Err(format!("Dependency not loaded {}", path))
106    }
107    pub fn null_texture(&self)->Texture{self.null_texture.clone()}
108    pub fn redraw_id(&self) -> u64 {self.redraw_id}
109    
110    pub fn os_type(&self) -> &OsType {&self.os_type}
111    pub fn in_makepad_studio(&self)->bool {self.in_makepad_studio}
112    
113    pub fn cpu_cores(&self) -> usize {self.cpu_cores}
114    pub fn gpu_info(&self) -> &GpuInfo {&self.gpu_info}
115    
116    pub fn update_macos_menu(&mut self, menu: MacosMenu) {
117        self.platform_ops.push(CxOsOp::UpdateMacosMenu(menu));
118    }
119    
120    pub fn quit(&mut self){
121        self.platform_ops.push(CxOsOp::Quit);
122    }
123    
124    pub fn push_unique_platform_op(&mut self, op: CxOsOp) {
125        if self.platform_ops.iter().find( | o | **o == op).is_none() {
126            self.platform_ops.push(op);
127        }
128    }
129    
130    pub fn show_text_ime(&mut self, area: Area, pos: DVec2) {
131        if !self.keyboard.text_ime_dismissed {
132            self.ime_area = area;
133            self.platform_ops.push(CxOsOp::ShowTextIME(area, pos));
134        }
135    }
136    
137    pub fn hide_text_ime(&mut self) {
138        self.keyboard.reset_text_ime_dismissed();
139        self.platform_ops.push(CxOsOp::HideTextIME);
140    }
141
142    pub fn text_ime_was_dismissed(&mut self) {
143        self.keyboard.set_text_ime_dismissed();
144        self.platform_ops.push(CxOsOp::HideTextIME);
145    }
146
147    pub fn show_clipboard_actions(&mut self, selected: String) {
148        self.platform_ops.push(CxOsOp::ShowClipboardActions(selected));
149    }
150
151    pub fn start_dragging(&mut self, items: Vec<DragItem>) {
152        self.platform_ops.iter().for_each( | p | {
153            if let CxOsOp::StartDragging{..} = p {
154                panic!("start drag twice");
155            }
156        });
157        self.platform_ops.push(CxOsOp::StartDragging(items));
158    }
159    
160    pub fn set_cursor(&mut self, cursor: MouseCursor) {
161        // down cursor overrides the hover cursor
162        if let Some(p) = self.platform_ops.iter_mut().find( | p | match p {
163            CxOsOp::SetCursor(_) => true,
164            _ => false
165        }) {
166            *p = CxOsOp::SetCursor(cursor)
167        }
168        else {
169            self.platform_ops.push(CxOsOp::SetCursor(cursor))
170        }
171    }
172    
173    pub fn sweep_lock(&mut self, value:Area){
174        self.fingers.sweep_lock(value);
175    }
176    
177    pub fn sweep_unlock(&mut self, value:Area){
178        self.fingers.sweep_unlock(value);
179    }
180    
181    pub fn start_timeout(&mut self, interval: f64) -> Timer {
182        self.timer_id += 1;
183        self.platform_ops.push(CxOsOp::StartTimer {
184            timer_id: self.timer_id,
185            interval,
186            repeats: false
187        });
188        Timer(self.timer_id)
189    }
190    
191    pub fn start_interval(&mut self, interval: f64) -> Timer {
192        self.timer_id += 1;
193        self.platform_ops.push(CxOsOp::StartTimer {
194            timer_id: self.timer_id,
195            interval,
196            repeats: true
197        });
198        Timer(self.timer_id)
199    }
200    
201    
202    
203    
204    pub fn stop_timer(&mut self, timer: Timer) {
205        if timer.0 != 0 {
206            self.platform_ops.push(CxOsOp::StopTimer(timer.0));
207        }
208    }
209    
210    pub fn xr_start_presenting(&mut self) {
211        self.platform_ops.push(CxOsOp::XrStartPresenting);
212    }
213    
214    pub fn xr_stop_presenting(&mut self) {
215        self.platform_ops.push(CxOsOp::XrStopPresenting);
216    }
217    
218    pub fn get_dpi_factor_of(&mut self, area: &Area) -> f64 {
219        if let Some(draw_list_id) = area.draw_list_id() {
220            let pass_id = self.draw_lists[draw_list_id].pass_id.unwrap();
221            return self.get_delegated_dpi_factor(pass_id)
222        }
223        return 1.0;
224    }
225    
226    pub fn get_delegated_dpi_factor(&mut self, pass_id: PassId) -> f64 {
227        let mut pass_id_walk = pass_id;
228        for _ in 0..25 {
229            match self.passes[pass_id_walk].parent {
230                CxPassParent::Window(window_id) => {
231                    if !self.windows[window_id].is_created {
232                        return 1.0
233                    }
234                    return self.windows[window_id].window_geom.dpi_factor;
235                },
236                CxPassParent::Pass(next_pass_id) => {
237                    pass_id_walk = next_pass_id;
238                },
239                _ => {break;}
240            }
241        }
242        1.0
243    }
244    
245    pub fn redraw_pass_and_parent_passes(&mut self, pass_id: PassId) {
246        let mut walk_pass_id = pass_id;
247        loop {
248            if let Some(main_list_id) = self.passes[walk_pass_id].main_draw_list_id {
249                self.redraw_list_and_children(main_list_id);
250            }
251            match self.passes[walk_pass_id].parent.clone() {
252                CxPassParent::Pass(next_pass_id) => {
253                    walk_pass_id = next_pass_id;
254                },
255                _ => {
256                    break;
257                }
258            }
259        } 
260    }
261    
262    pub fn get_pass_rect(&self, pass_id: PassId, dpi:f64) -> Option<Rect> {
263        match self.passes[pass_id].pass_rect {
264            Some(CxPassRect::Area(area)) => {
265                let rect = area.get_rect(self);
266                Some(Rect{
267                    pos: (rect.pos * dpi).floor() / dpi,
268                    size: (rect.size * dpi).ceil() / dpi
269                })
270            }
271            Some(CxPassRect::ScaledArea(area, scale)) => {
272                let rect = area.get_rect(self);
273                Some(Rect{
274                    pos: (rect.pos * dpi).floor() / dpi,
275                    size:  scale * (rect.size * dpi).ceil() / dpi
276                })
277            }
278            Some(CxPassRect::Size(size)) => Some(Rect {pos: DVec2::default(), size: (size / dpi).floor() * dpi}),
279            None => None
280        } 
281    }
282    
283    pub fn get_pass_rect2(&self, pass_id: PassId, dpi:f64) -> Option<Rect> {
284        match self.passes[pass_id].pass_rect {
285            Some(CxPassRect::Area(area)) => {
286                let rect = area.get_rect(self);
287                Some(Rect{
288                    pos: (rect.pos * dpi).floor() / dpi,
289                    size: (rect.size * dpi).ceil() / dpi
290                })
291            }
292            Some(CxPassRect::ScaledArea(area, scale)) => {
293                let rect = area.get_rect(self);
294                Some(Rect{
295                    pos: (rect.pos * dpi).floor() / dpi,
296                    size:  scale * (rect.size * dpi).ceil() / dpi
297                })
298            }
299            Some(CxPassRect::Size(size)) => {
300                Some(Rect {pos: DVec2::default(), size: (size * dpi).floor() / dpi})
301            }
302            None => None
303        } 
304    }
305    
306    pub fn get_pass_name(&self, pass_id: PassId) -> &str {
307        &self.passes[pass_id].debug_name
308    }
309    
310    pub fn repaint_pass(&mut self, pass_id: PassId) {
311        let cxpass = &mut self.passes[pass_id];
312        cxpass.paint_dirty = true;
313    }
314    
315    pub fn repaint_pass_and_child_passes(&mut self, pass_id: PassId) {
316        let cxpass = &mut self.passes[pass_id];
317        cxpass.paint_dirty = true;
318        for sub_pass_id in self.passes.id_iter() {
319            if let CxPassParent::Pass(dep_pass_id) = self.passes[sub_pass_id].parent.clone() {
320                if dep_pass_id == pass_id {
321                    self.repaint_pass_and_child_passes(sub_pass_id);
322                }
323            }
324        }
325    }
326    
327    pub fn redraw_pass_and_child_passes(&mut self, pass_id: PassId) {
328        let cxpass = &self.passes[pass_id];
329        if let Some(main_list_id) = cxpass.main_draw_list_id {
330            self.redraw_list_and_children(main_list_id);
331        }
332        // lets redraw all subpasses as well
333        for sub_pass_id in self.passes.id_iter() {
334            if let CxPassParent::Pass(dep_pass_id) = self.passes[sub_pass_id].parent.clone() {
335                if dep_pass_id == pass_id {
336                    self.redraw_pass_and_child_passes(sub_pass_id);
337                }
338            }
339        }
340    }
341    
342    pub fn redraw_all(&mut self) {
343        self.new_draw_event.redraw_all = true;
344    }
345    
346    pub fn redraw_area(&mut self, area: Area) {
347        if let Some(draw_list_id) = area.draw_list_id() {
348            self.redraw_list(draw_list_id);
349        }
350    }
351    
352    pub fn redraw_area_and_children(&mut self, area: Area) {
353        if let Some(draw_list_id) = area.draw_list_id() {
354            self.redraw_list_and_children(draw_list_id);
355        }
356    }
357    
358    pub fn redraw_list(&mut self, draw_list_id: DrawListId) {
359        if self.new_draw_event.draw_lists.iter().position( | v | *v == draw_list_id).is_some() {
360            return;
361        }
362        self.new_draw_event.draw_lists.push(draw_list_id);
363    }
364    
365    pub fn redraw_list_and_children(&mut self, draw_list_id: DrawListId) {
366        if self.new_draw_event.draw_lists_and_children.iter().position( | v | *v == draw_list_id).is_some() {
367            return;
368        }
369        self.new_draw_event.draw_lists_and_children.push(draw_list_id);
370    }
371    
372    pub fn get_ime_area_rect(&self)->Rect{
373        self.ime_area.get_rect(self)
374    }
375    
376    pub fn update_area_refs(&mut self, old_area: Area, new_area: Area) -> Area {
377        if old_area == Area::Empty {
378            return new_area
379        }
380        if self.ime_area == old_area {
381            self.ime_area = new_area;
382        }
383        self.fingers.update_area(old_area, new_area);
384        self.drag_drop.update_area(old_area, new_area);
385        self.keyboard.update_area(old_area, new_area);
386        
387        new_area
388    }
389    
390    pub fn set_key_focus(&mut self, focus_area: Area) {
391        self.keyboard.set_key_focus(focus_area);
392    }
393    
394    pub fn revert_key_focus(&mut self) {
395        self.keyboard.revert_key_focus();
396    }
397    
398    pub fn has_key_focus(&self, focus_area: Area) -> bool {
399        self.keyboard.has_key_focus(focus_area)
400    }
401    
402    pub fn new_next_frame(&mut self) -> NextFrame {
403        let res = NextFrame(self.next_frame_id);
404        self.next_frame_id += 1;
405        self.new_next_frames.insert(res);
406        res
407    }
408    
409    pub fn send_trigger(&mut self, area: Area, trigger: Trigger) {
410        if let Some(triggers) = self.triggers.get_mut(&area) {
411            triggers.push(trigger);
412        }
413        else {
414            let mut new_set = Vec::new();
415            new_set.push(trigger);
416            self.triggers.insert(area, new_set);
417        }
418    }
419    
420    pub fn set_global<T: 'static + Any + Sized>(&mut self, value: T) {
421        if !self.globals.iter().any( | v | v.0 == TypeId::of::<T>()) {
422            self.globals.push((TypeId::of::<T>(), Box::new(value)));
423        }
424    }
425    
426    pub fn get_global<T: 'static + Any>(&mut self) -> &mut T {
427        let item = self.globals.iter_mut().find( | v | v.0 == TypeId::of::<T>()).unwrap();
428        item.1.downcast_mut().unwrap()
429    }
430    
431    pub fn has_global<T: 'static + Any>(&mut self) -> bool {
432        self.globals.iter_mut().find( | v | v.0 == TypeId::of::<T>()).is_some()
433    }
434    
435    pub fn global<T: 'static + Any + Default>(&mut self) -> &mut T {
436        if !self.has_global::<T>() {
437            self.set_global(T::default());
438        }
439        self.get_global::<T>()
440    }
441
442    pub fn spawner(&self) -> &Spawner {
443        &self.spawner
444    }
445
446    pub fn http_request(&mut self, request_id: LiveId, request: HttpRequest) {
447        self.platform_ops.push(CxOsOp::HttpRequest{request_id, request});
448    }
449           
450    pub fn web_socket_open(&mut self, request_id: LiveId, request: HttpRequest) {
451        self.platform_ops.push(CxOsOp::WebSocketOpen{
452            request,
453            request_id,
454        });
455    }
456    
457    pub fn web_socket_send_binary(&mut self, request_id: LiveId, data: Vec<u8>) {
458        self.platform_ops.push(CxOsOp::WebSocketSendBinary{
459            request_id,
460            data,
461        });
462    }
463
464    pub fn initialize_video_decoding(&mut self, video_id: LiveId, video: Rc<Vec<u8>>, chunk_size: usize) {
465        self.platform_ops.push(CxOsOp::InitializeVideoDecoding(video_id, video, chunk_size));
466    }
467
468    pub fn decode_next_video_chunk(&mut self, video_id: LiveId, max_frames_to_decode: usize) {
469        self.platform_ops.push(CxOsOp::DecodeNextVideoChunk(video_id, max_frames_to_decode));
470    }
471
472    pub fn fetch_next_video_frames(&mut self, video_id: LiveId, number_frames: usize) {
473        self.platform_ops.push(CxOsOp::FetchNextVideoFrames(video_id, number_frames));
474    }
475
476    pub fn cleanup_video_decoding(&mut self, video_id: LiveId) {
477        self.platform_ops.push(CxOsOp::CleanupVideoDecoding(video_id));
478    }
479    
480    pub fn println_resources(&self){
481        println!("Num textures: {}",self.textures.0.pool.len());
482    }
483}
484
485#[macro_export]
486macro_rules!register_component_factory {
487    ( $ cx: ident, $ registry: ident, $ ty: ty, $ factory: ident) => {
488        let module_id = LiveModuleId::from_str(&module_path!()).unwrap();
489        if let Some((reg, _)) = $ cx.live_registry.borrow().components.get_or_create::< $ registry>().map.get(&LiveType::of::< $ ty>()) {
490            if reg.module_id != module_id {
491                panic!("Component already registered {} {}", stringify!( $ ty), reg.module_id);
492            }
493        }
494        $ cx.live_registry.borrow().components.get_or_create::< $ registry>().map.insert(
495            LiveType::of::< $ ty>(),
496            (LiveComponentInfo {
497                name: LiveId::from_str_with_lut(stringify!( $ ty)).unwrap(),
498                module_id
499            }, Box::new( $ factory()))
500        );
501    }
502}