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 },
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 }
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 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 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}