1pub mod proto;
21
22#[link(wasm_import_module = "oxide")]
25extern "C" {
26 #[link_name = "api_log"]
27 fn _api_log(ptr: u32, len: u32);
28
29 #[link_name = "api_warn"]
30 fn _api_warn(ptr: u32, len: u32);
31
32 #[link_name = "api_error"]
33 fn _api_error(ptr: u32, len: u32);
34
35 #[link_name = "api_get_location"]
36 fn _api_get_location(out_ptr: u32, out_cap: u32) -> u32;
37
38 #[link_name = "api_upload_file"]
39 fn _api_upload_file(name_ptr: u32, name_cap: u32, data_ptr: u32, data_cap: u32) -> u64;
40
41 #[link_name = "api_canvas_clear"]
42 fn _api_canvas_clear(r: u32, g: u32, b: u32, a: u32);
43
44 #[link_name = "api_canvas_rect"]
45 fn _api_canvas_rect(x: f32, y: f32, w: f32, h: f32, r: u32, g: u32, b: u32, a: u32);
46
47 #[link_name = "api_canvas_circle"]
48 fn _api_canvas_circle(cx: f32, cy: f32, radius: f32, r: u32, g: u32, b: u32, a: u32);
49
50 #[link_name = "api_canvas_text"]
51 fn _api_canvas_text(x: f32, y: f32, size: f32, r: u32, g: u32, b: u32, ptr: u32, len: u32);
52
53 #[link_name = "api_canvas_line"]
54 fn _api_canvas_line(x1: f32, y1: f32, x2: f32, y2: f32, r: u32, g: u32, b: u32, thickness: f32);
55
56 #[link_name = "api_canvas_dimensions"]
57 fn _api_canvas_dimensions() -> u64;
58
59 #[link_name = "api_canvas_image"]
60 fn _api_canvas_image(x: f32, y: f32, w: f32, h: f32, data_ptr: u32, data_len: u32);
61
62 #[link_name = "api_storage_set"]
63 fn _api_storage_set(key_ptr: u32, key_len: u32, val_ptr: u32, val_len: u32);
64
65 #[link_name = "api_storage_get"]
66 fn _api_storage_get(key_ptr: u32, key_len: u32, out_ptr: u32, out_cap: u32) -> u32;
67
68 #[link_name = "api_storage_remove"]
69 fn _api_storage_remove(key_ptr: u32, key_len: u32);
70
71 #[link_name = "api_clipboard_write"]
72 fn _api_clipboard_write(ptr: u32, len: u32);
73
74 #[link_name = "api_clipboard_read"]
75 fn _api_clipboard_read(out_ptr: u32, out_cap: u32) -> u32;
76
77 #[link_name = "api_time_now_ms"]
78 fn _api_time_now_ms() -> u64;
79
80 #[link_name = "api_random"]
81 fn _api_random() -> u64;
82
83 #[link_name = "api_notify"]
84 fn _api_notify(title_ptr: u32, title_len: u32, body_ptr: u32, body_len: u32);
85
86 #[link_name = "api_fetch"]
87 fn _api_fetch(
88 method_ptr: u32,
89 method_len: u32,
90 url_ptr: u32,
91 url_len: u32,
92 ct_ptr: u32,
93 ct_len: u32,
94 body_ptr: u32,
95 body_len: u32,
96 out_ptr: u32,
97 out_cap: u32,
98 ) -> i64;
99
100 #[link_name = "api_load_module"]
101 fn _api_load_module(url_ptr: u32, url_len: u32) -> i32;
102
103 #[link_name = "api_hash_sha256"]
104 fn _api_hash_sha256(data_ptr: u32, data_len: u32, out_ptr: u32) -> u32;
105
106 #[link_name = "api_base64_encode"]
107 fn _api_base64_encode(data_ptr: u32, data_len: u32, out_ptr: u32, out_cap: u32) -> u32;
108
109 #[link_name = "api_base64_decode"]
110 fn _api_base64_decode(data_ptr: u32, data_len: u32, out_ptr: u32, out_cap: u32) -> u32;
111
112 #[link_name = "api_kv_store_set"]
113 fn _api_kv_store_set(key_ptr: u32, key_len: u32, val_ptr: u32, val_len: u32) -> i32;
114
115 #[link_name = "api_kv_store_get"]
116 fn _api_kv_store_get(key_ptr: u32, key_len: u32, out_ptr: u32, out_cap: u32) -> i32;
117
118 #[link_name = "api_kv_store_delete"]
119 fn _api_kv_store_delete(key_ptr: u32, key_len: u32) -> i32;
120
121 #[link_name = "api_navigate"]
124 fn _api_navigate(url_ptr: u32, url_len: u32) -> i32;
125
126 #[link_name = "api_push_state"]
127 fn _api_push_state(
128 state_ptr: u32,
129 state_len: u32,
130 title_ptr: u32,
131 title_len: u32,
132 url_ptr: u32,
133 url_len: u32,
134 );
135
136 #[link_name = "api_replace_state"]
137 fn _api_replace_state(
138 state_ptr: u32,
139 state_len: u32,
140 title_ptr: u32,
141 title_len: u32,
142 url_ptr: u32,
143 url_len: u32,
144 );
145
146 #[link_name = "api_get_url"]
147 fn _api_get_url(out_ptr: u32, out_cap: u32) -> u32;
148
149 #[link_name = "api_get_state"]
150 fn _api_get_state(out_ptr: u32, out_cap: u32) -> i32;
151
152 #[link_name = "api_history_length"]
153 fn _api_history_length() -> u32;
154
155 #[link_name = "api_history_back"]
156 fn _api_history_back() -> i32;
157
158 #[link_name = "api_history_forward"]
159 fn _api_history_forward() -> i32;
160
161 #[link_name = "api_register_hyperlink"]
164 fn _api_register_hyperlink(x: f32, y: f32, w: f32, h: f32, url_ptr: u32, url_len: u32) -> i32;
165
166 #[link_name = "api_clear_hyperlinks"]
167 fn _api_clear_hyperlinks();
168
169 #[link_name = "api_mouse_position"]
172 fn _api_mouse_position() -> u64;
173
174 #[link_name = "api_mouse_button_down"]
175 fn _api_mouse_button_down(button: u32) -> u32;
176
177 #[link_name = "api_mouse_button_clicked"]
178 fn _api_mouse_button_clicked(button: u32) -> u32;
179
180 #[link_name = "api_key_down"]
181 fn _api_key_down(key: u32) -> u32;
182
183 #[link_name = "api_key_pressed"]
184 fn _api_key_pressed(key: u32) -> u32;
185
186 #[link_name = "api_scroll_delta"]
187 fn _api_scroll_delta() -> u64;
188
189 #[link_name = "api_modifiers"]
190 fn _api_modifiers() -> u32;
191
192 #[link_name = "api_ui_button"]
195 fn _api_ui_button(
196 id: u32,
197 x: f32,
198 y: f32,
199 w: f32,
200 h: f32,
201 label_ptr: u32,
202 label_len: u32,
203 ) -> u32;
204
205 #[link_name = "api_ui_checkbox"]
206 fn _api_ui_checkbox(
207 id: u32,
208 x: f32,
209 y: f32,
210 label_ptr: u32,
211 label_len: u32,
212 initial: u32,
213 ) -> u32;
214
215 #[link_name = "api_ui_slider"]
216 fn _api_ui_slider(id: u32, x: f32, y: f32, w: f32, min: f32, max: f32, initial: f32) -> f32;
217
218 #[link_name = "api_ui_text_input"]
219 fn _api_ui_text_input(
220 id: u32,
221 x: f32,
222 y: f32,
223 w: f32,
224 init_ptr: u32,
225 init_len: u32,
226 out_ptr: u32,
227 out_cap: u32,
228 ) -> u32;
229
230 #[link_name = "api_url_resolve"]
233 fn _api_url_resolve(
234 base_ptr: u32,
235 base_len: u32,
236 rel_ptr: u32,
237 rel_len: u32,
238 out_ptr: u32,
239 out_cap: u32,
240 ) -> i32;
241
242 #[link_name = "api_url_encode"]
243 fn _api_url_encode(input_ptr: u32, input_len: u32, out_ptr: u32, out_cap: u32) -> u32;
244
245 #[link_name = "api_url_decode"]
246 fn _api_url_decode(input_ptr: u32, input_len: u32, out_ptr: u32, out_cap: u32) -> u32;
247}
248
249pub fn log(msg: &str) {
253 unsafe { _api_log(msg.as_ptr() as u32, msg.len() as u32) }
254}
255
256pub fn warn(msg: &str) {
258 unsafe { _api_warn(msg.as_ptr() as u32, msg.len() as u32) }
259}
260
261pub fn error(msg: &str) {
263 unsafe { _api_error(msg.as_ptr() as u32, msg.len() as u32) }
264}
265
266pub fn get_location() -> String {
270 let mut buf = [0u8; 128];
271 let len = unsafe { _api_get_location(buf.as_mut_ptr() as u32, buf.len() as u32) };
272 String::from_utf8_lossy(&buf[..len as usize]).to_string()
273}
274
275pub struct UploadedFile {
279 pub name: String,
280 pub data: Vec<u8>,
281}
282
283pub fn upload_file() -> Option<UploadedFile> {
286 let mut name_buf = [0u8; 256];
287 let mut data_buf = vec![0u8; 1024 * 1024]; let result = unsafe {
290 _api_upload_file(
291 name_buf.as_mut_ptr() as u32,
292 name_buf.len() as u32,
293 data_buf.as_mut_ptr() as u32,
294 data_buf.len() as u32,
295 )
296 };
297
298 if result == 0 {
299 return None;
300 }
301
302 let name_len = (result >> 32) as usize;
303 let data_len = (result & 0xFFFF_FFFF) as usize;
304
305 Some(UploadedFile {
306 name: String::from_utf8_lossy(&name_buf[..name_len]).to_string(),
307 data: data_buf[..data_len].to_vec(),
308 })
309}
310
311pub fn canvas_clear(r: u8, g: u8, b: u8, a: u8) {
315 unsafe { _api_canvas_clear(r as u32, g as u32, b as u32, a as u32) }
316}
317
318pub fn canvas_rect(x: f32, y: f32, w: f32, h: f32, r: u8, g: u8, b: u8, a: u8) {
320 unsafe { _api_canvas_rect(x, y, w, h, r as u32, g as u32, b as u32, a as u32) }
321}
322
323pub fn canvas_circle(cx: f32, cy: f32, radius: f32, r: u8, g: u8, b: u8, a: u8) {
325 unsafe { _api_canvas_circle(cx, cy, radius, r as u32, g as u32, b as u32, a as u32) }
326}
327
328pub fn canvas_text(x: f32, y: f32, size: f32, r: u8, g: u8, b: u8, text: &str) {
330 unsafe {
331 _api_canvas_text(
332 x,
333 y,
334 size,
335 r as u32,
336 g as u32,
337 b as u32,
338 text.as_ptr() as u32,
339 text.len() as u32,
340 )
341 }
342}
343
344pub fn canvas_line(x1: f32, y1: f32, x2: f32, y2: f32, r: u8, g: u8, b: u8, thickness: f32) {
346 unsafe { _api_canvas_line(x1, y1, x2, y2, r as u32, g as u32, b as u32, thickness) }
347}
348
349pub fn canvas_dimensions() -> (u32, u32) {
351 let packed = unsafe { _api_canvas_dimensions() };
352 ((packed >> 32) as u32, (packed & 0xFFFF_FFFF) as u32)
353}
354
355pub fn canvas_image(x: f32, y: f32, w: f32, h: f32, data: &[u8]) {
358 unsafe { _api_canvas_image(x, y, w, h, data.as_ptr() as u32, data.len() as u32) }
359}
360
361pub fn storage_set(key: &str, value: &str) {
365 unsafe {
366 _api_storage_set(
367 key.as_ptr() as u32,
368 key.len() as u32,
369 value.as_ptr() as u32,
370 value.len() as u32,
371 )
372 }
373}
374
375pub fn storage_get(key: &str) -> String {
377 let mut buf = [0u8; 4096];
378 let len = unsafe {
379 _api_storage_get(
380 key.as_ptr() as u32,
381 key.len() as u32,
382 buf.as_mut_ptr() as u32,
383 buf.len() as u32,
384 )
385 };
386 String::from_utf8_lossy(&buf[..len as usize]).to_string()
387}
388
389pub fn storage_remove(key: &str) {
391 unsafe { _api_storage_remove(key.as_ptr() as u32, key.len() as u32) }
392}
393
394pub fn clipboard_write(text: &str) {
398 unsafe { _api_clipboard_write(text.as_ptr() as u32, text.len() as u32) }
399}
400
401pub fn clipboard_read() -> String {
403 let mut buf = [0u8; 4096];
404 let len = unsafe { _api_clipboard_read(buf.as_mut_ptr() as u32, buf.len() as u32) };
405 String::from_utf8_lossy(&buf[..len as usize]).to_string()
406}
407
408pub fn time_now_ms() -> u64 {
412 unsafe { _api_time_now_ms() }
413}
414
415pub fn random_u64() -> u64 {
419 unsafe { _api_random() }
420}
421
422pub fn random_f64() -> f64 {
424 (random_u64() >> 11) as f64 / (1u64 << 53) as f64
425}
426
427pub fn notify(title: &str, body: &str) {
431 unsafe {
432 _api_notify(
433 title.as_ptr() as u32,
434 title.len() as u32,
435 body.as_ptr() as u32,
436 body.len() as u32,
437 )
438 }
439}
440
441pub struct FetchResponse {
445 pub status: u32,
446 pub body: Vec<u8>,
447}
448
449impl FetchResponse {
450 pub fn text(&self) -> String {
452 String::from_utf8_lossy(&self.body).to_string()
453 }
454}
455
456pub fn fetch(
462 method: &str,
463 url: &str,
464 content_type: &str,
465 body: &[u8],
466) -> Result<FetchResponse, i64> {
467 let mut out_buf = vec![0u8; 4 * 1024 * 1024]; let result = unsafe {
469 _api_fetch(
470 method.as_ptr() as u32,
471 method.len() as u32,
472 url.as_ptr() as u32,
473 url.len() as u32,
474 content_type.as_ptr() as u32,
475 content_type.len() as u32,
476 body.as_ptr() as u32,
477 body.len() as u32,
478 out_buf.as_mut_ptr() as u32,
479 out_buf.len() as u32,
480 )
481 };
482 if result < 0 {
483 return Err(result);
484 }
485 let status = (result >> 32) as u32;
486 let body_len = (result & 0xFFFF_FFFF) as usize;
487 Ok(FetchResponse {
488 status,
489 body: out_buf[..body_len].to_vec(),
490 })
491}
492
493pub fn fetch_get(url: &str) -> Result<FetchResponse, i64> {
495 fetch("GET", url, "", &[])
496}
497
498pub fn fetch_post(url: &str, content_type: &str, body: &[u8]) -> Result<FetchResponse, i64> {
500 fetch("POST", url, content_type, body)
501}
502
503pub fn fetch_post_proto(url: &str, msg: &proto::ProtoEncoder) -> Result<FetchResponse, i64> {
505 fetch("POST", url, "application/protobuf", msg.as_bytes())
506}
507
508pub fn fetch_put(url: &str, content_type: &str, body: &[u8]) -> Result<FetchResponse, i64> {
510 fetch("PUT", url, content_type, body)
511}
512
513pub fn fetch_delete(url: &str) -> Result<FetchResponse, i64> {
515 fetch("DELETE", url, "", &[])
516}
517
518pub fn load_module(url: &str) -> i32 {
524 unsafe { _api_load_module(url.as_ptr() as u32, url.len() as u32) }
525}
526
527pub fn hash_sha256(data: &[u8]) -> [u8; 32] {
531 let mut out = [0u8; 32];
532 unsafe {
533 _api_hash_sha256(
534 data.as_ptr() as u32,
535 data.len() as u32,
536 out.as_mut_ptr() as u32,
537 );
538 }
539 out
540}
541
542pub fn hash_sha256_hex(data: &[u8]) -> String {
544 let hash = hash_sha256(data);
545 let mut hex = String::with_capacity(64);
546 for byte in &hash {
547 hex.push(HEX_CHARS[(*byte >> 4) as usize]);
548 hex.push(HEX_CHARS[(*byte & 0x0F) as usize]);
549 }
550 hex
551}
552
553const HEX_CHARS: [char; 16] = [
554 '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f',
555];
556
557pub fn base64_encode(data: &[u8]) -> String {
561 let mut buf = vec![0u8; data.len() * 4 / 3 + 8];
562 let len = unsafe {
563 _api_base64_encode(
564 data.as_ptr() as u32,
565 data.len() as u32,
566 buf.as_mut_ptr() as u32,
567 buf.len() as u32,
568 )
569 };
570 String::from_utf8_lossy(&buf[..len as usize]).to_string()
571}
572
573pub fn base64_decode(encoded: &str) -> Vec<u8> {
575 let mut buf = vec![0u8; encoded.len()];
576 let len = unsafe {
577 _api_base64_decode(
578 encoded.as_ptr() as u32,
579 encoded.len() as u32,
580 buf.as_mut_ptr() as u32,
581 buf.len() as u32,
582 )
583 };
584 buf[..len as usize].to_vec()
585}
586
587pub fn kv_store_set(key: &str, value: &[u8]) -> bool {
592 let rc = unsafe {
593 _api_kv_store_set(
594 key.as_ptr() as u32,
595 key.len() as u32,
596 value.as_ptr() as u32,
597 value.len() as u32,
598 )
599 };
600 rc == 0
601}
602
603pub fn kv_store_set_str(key: &str, value: &str) -> bool {
605 kv_store_set(key, value.as_bytes())
606}
607
608pub fn kv_store_get(key: &str) -> Option<Vec<u8>> {
611 let mut buf = vec![0u8; 64 * 1024]; let rc = unsafe {
613 _api_kv_store_get(
614 key.as_ptr() as u32,
615 key.len() as u32,
616 buf.as_mut_ptr() as u32,
617 buf.len() as u32,
618 )
619 };
620 if rc < 0 {
621 return None;
622 }
623 Some(buf[..rc as usize].to_vec())
624}
625
626pub fn kv_store_get_str(key: &str) -> Option<String> {
628 kv_store_get(key).map(|v| String::from_utf8_lossy(&v).into_owned())
629}
630
631pub fn kv_store_delete(key: &str) -> bool {
633 let rc = unsafe { _api_kv_store_delete(key.as_ptr() as u32, key.len() as u32) };
634 rc == 0
635}
636
637pub fn navigate(url: &str) -> i32 {
643 unsafe { _api_navigate(url.as_ptr() as u32, url.len() as u32) }
644}
645
646pub fn push_state(state: &[u8], title: &str, url: &str) {
654 unsafe {
655 _api_push_state(
656 state.as_ptr() as u32,
657 state.len() as u32,
658 title.as_ptr() as u32,
659 title.len() as u32,
660 url.as_ptr() as u32,
661 url.len() as u32,
662 )
663 }
664}
665
666pub fn replace_state(state: &[u8], title: &str, url: &str) {
669 unsafe {
670 _api_replace_state(
671 state.as_ptr() as u32,
672 state.len() as u32,
673 title.as_ptr() as u32,
674 title.len() as u32,
675 url.as_ptr() as u32,
676 url.len() as u32,
677 )
678 }
679}
680
681pub fn get_url() -> String {
683 let mut buf = [0u8; 4096];
684 let len = unsafe { _api_get_url(buf.as_mut_ptr() as u32, buf.len() as u32) };
685 String::from_utf8_lossy(&buf[..len as usize]).to_string()
686}
687
688pub fn get_state() -> Option<Vec<u8>> {
691 let mut buf = vec![0u8; 64 * 1024]; let rc = unsafe { _api_get_state(buf.as_mut_ptr() as u32, buf.len() as u32) };
693 if rc < 0 {
694 return None;
695 }
696 Some(buf[..rc as usize].to_vec())
697}
698
699pub fn history_length() -> u32 {
701 unsafe { _api_history_length() }
702}
703
704pub fn history_back() -> bool {
706 unsafe { _api_history_back() == 1 }
707}
708
709pub fn history_forward() -> bool {
711 unsafe { _api_history_forward() == 1 }
712}
713
714pub fn register_hyperlink(x: f32, y: f32, w: f32, h: f32, url: &str) -> i32 {
722 unsafe { _api_register_hyperlink(x, y, w, h, url.as_ptr() as u32, url.len() as u32) }
723}
724
725pub fn clear_hyperlinks() {
727 unsafe { _api_clear_hyperlinks() }
728}
729
730pub fn url_resolve(base: &str, relative: &str) -> Option<String> {
735 let mut buf = [0u8; 4096];
736 let rc = unsafe {
737 _api_url_resolve(
738 base.as_ptr() as u32,
739 base.len() as u32,
740 relative.as_ptr() as u32,
741 relative.len() as u32,
742 buf.as_mut_ptr() as u32,
743 buf.len() as u32,
744 )
745 };
746 if rc < 0 {
747 return None;
748 }
749 Some(String::from_utf8_lossy(&buf[..rc as usize]).to_string())
750}
751
752pub fn url_encode(input: &str) -> String {
754 let mut buf = vec![0u8; input.len() * 3 + 4];
755 let len = unsafe {
756 _api_url_encode(
757 input.as_ptr() as u32,
758 input.len() as u32,
759 buf.as_mut_ptr() as u32,
760 buf.len() as u32,
761 )
762 };
763 String::from_utf8_lossy(&buf[..len as usize]).to_string()
764}
765
766pub fn url_decode(input: &str) -> String {
768 let mut buf = vec![0u8; input.len() + 4];
769 let len = unsafe {
770 _api_url_decode(
771 input.as_ptr() as u32,
772 input.len() as u32,
773 buf.as_mut_ptr() as u32,
774 buf.len() as u32,
775 )
776 };
777 String::from_utf8_lossy(&buf[..len as usize]).to_string()
778}
779
780pub fn mouse_position() -> (f32, f32) {
784 let packed = unsafe { _api_mouse_position() };
785 let x = f32::from_bits((packed >> 32) as u32);
786 let y = f32::from_bits((packed & 0xFFFF_FFFF) as u32);
787 (x, y)
788}
789
790pub fn mouse_button_down(button: u32) -> bool {
793 unsafe { _api_mouse_button_down(button) != 0 }
794}
795
796pub fn mouse_button_clicked(button: u32) -> bool {
798 unsafe { _api_mouse_button_clicked(button) != 0 }
799}
800
801pub fn key_down(key: u32) -> bool {
804 unsafe { _api_key_down(key) != 0 }
805}
806
807pub fn key_pressed(key: u32) -> bool {
809 unsafe { _api_key_pressed(key) != 0 }
810}
811
812pub fn scroll_delta() -> (f32, f32) {
814 let packed = unsafe { _api_scroll_delta() };
815 let x = f32::from_bits((packed >> 32) as u32);
816 let y = f32::from_bits((packed & 0xFFFF_FFFF) as u32);
817 (x, y)
818}
819
820pub fn modifiers() -> u32 {
822 unsafe { _api_modifiers() }
823}
824
825pub fn shift_held() -> bool {
827 modifiers() & 1 != 0
828}
829
830pub fn ctrl_held() -> bool {
832 modifiers() & 2 != 0
833}
834
835pub fn alt_held() -> bool {
837 modifiers() & 4 != 0
838}
839
840pub const KEY_A: u32 = 0;
843pub const KEY_B: u32 = 1;
844pub const KEY_C: u32 = 2;
845pub const KEY_D: u32 = 3;
846pub const KEY_E: u32 = 4;
847pub const KEY_F: u32 = 5;
848pub const KEY_G: u32 = 6;
849pub const KEY_H: u32 = 7;
850pub const KEY_I: u32 = 8;
851pub const KEY_J: u32 = 9;
852pub const KEY_K: u32 = 10;
853pub const KEY_L: u32 = 11;
854pub const KEY_M: u32 = 12;
855pub const KEY_N: u32 = 13;
856pub const KEY_O: u32 = 14;
857pub const KEY_P: u32 = 15;
858pub const KEY_Q: u32 = 16;
859pub const KEY_R: u32 = 17;
860pub const KEY_S: u32 = 18;
861pub const KEY_T: u32 = 19;
862pub const KEY_U: u32 = 20;
863pub const KEY_V: u32 = 21;
864pub const KEY_W: u32 = 22;
865pub const KEY_X: u32 = 23;
866pub const KEY_Y: u32 = 24;
867pub const KEY_Z: u32 = 25;
868pub const KEY_0: u32 = 26;
869pub const KEY_1: u32 = 27;
870pub const KEY_2: u32 = 28;
871pub const KEY_3: u32 = 29;
872pub const KEY_4: u32 = 30;
873pub const KEY_5: u32 = 31;
874pub const KEY_6: u32 = 32;
875pub const KEY_7: u32 = 33;
876pub const KEY_8: u32 = 34;
877pub const KEY_9: u32 = 35;
878pub const KEY_ENTER: u32 = 36;
879pub const KEY_ESCAPE: u32 = 37;
880pub const KEY_TAB: u32 = 38;
881pub const KEY_BACKSPACE: u32 = 39;
882pub const KEY_DELETE: u32 = 40;
883pub const KEY_SPACE: u32 = 41;
884pub const KEY_UP: u32 = 42;
885pub const KEY_DOWN: u32 = 43;
886pub const KEY_LEFT: u32 = 44;
887pub const KEY_RIGHT: u32 = 45;
888pub const KEY_HOME: u32 = 46;
889pub const KEY_END: u32 = 47;
890pub const KEY_PAGE_UP: u32 = 48;
891pub const KEY_PAGE_DOWN: u32 = 49;
892
893pub fn ui_button(id: u32, x: f32, y: f32, w: f32, h: f32, label: &str) -> bool {
901 unsafe { _api_ui_button(id, x, y, w, h, label.as_ptr() as u32, label.len() as u32) != 0 }
902}
903
904pub fn ui_checkbox(id: u32, x: f32, y: f32, label: &str, initial: bool) -> bool {
908 unsafe {
909 _api_ui_checkbox(
910 id,
911 x,
912 y,
913 label.as_ptr() as u32,
914 label.len() as u32,
915 if initial { 1 } else { 0 },
916 ) != 0
917 }
918}
919
920pub fn ui_slider(id: u32, x: f32, y: f32, w: f32, min: f32, max: f32, initial: f32) -> f32 {
924 unsafe { _api_ui_slider(id, x, y, w, min, max, initial) }
925}
926
927pub fn ui_text_input(id: u32, x: f32, y: f32, w: f32, initial: &str) -> String {
931 let mut buf = [0u8; 4096];
932 let len = unsafe {
933 _api_ui_text_input(
934 id,
935 x,
936 y,
937 w,
938 initial.as_ptr() as u32,
939 initial.len() as u32,
940 buf.as_mut_ptr() as u32,
941 buf.len() as u32,
942 )
943 };
944 String::from_utf8_lossy(&buf[..len as usize]).to_string()
945}