1use alloc::rc::Rc;
20use alloc::vec::Vec;
21
22use super::cmd::Gfx;
23use super::consts::*;
24use super::Ui;
25use gfx::{Surface, FMT_PARGB};
26
27pub type CursorDraw = Rc<dyn Fn(&mut Gfx, i32)>;
29
30#[derive(Clone)]
32struct UCur {
33 f: CursorDraw,
34 w: u32,
35 h: u32,
36 hot: u32,
37 plat: i32,
39 dpi: u32,
40}
41
42#[derive(Default)]
44pub(crate) struct S {
45 slots: Vec<Option<UCur>>,
46 cur: u32,
47}
48
49fn uc_px(dip: u32, dpi: u32) -> u32 {
51 dip.wrapping_mul(dpi).wrapping_add(95) / 96
52}
53
54impl Ui {
55 pub fn cursor_new(&mut self, f: CursorDraw, w: u32, h: u32, hot: u32) -> u32 {
57 let s = &mut self.ucur.slots;
58 if s.is_empty() {
59 s.resize(CUR_USER_MAX as usize, None);
60 }
61 let Some(i) = s.iter().position(|x| x.is_none()) else { return 0 };
62 s[i] = Some(UCur { f, w, h, hot, plat: -1, dpi: 0 });
63 i as u32 + 1
64 }
65
66 pub fn cursor_custom(&mut self, h: u32) {
68 self.ucur.cur = h;
69 }
70
71 pub fn cursor_current(&self) -> u32 {
73 self.ucur.cur
74 }
75
76 fn uc_rec(&self, h: u32) -> Option<&UCur> {
78 let i = h.wrapping_sub(1);
79 if i >= CUR_USER_MAX {
80 return None;
81 }
82 self.ucur.slots.get(i as usize)?.as_ref()
83 }
84
85 pub fn cursor_render(&mut self, h: u32, dpi: i32) -> Option<Surface> {
87 let r = self.uc_rec(h)?.clone();
88 if (dpi as u32).wrapping_sub(24) > 960 - 24 {
89 return None; }
91 let w = uc_px(r.w, dpi as u32);
92 let hh = uc_px(r.h, dpi as u32);
93 if w.wrapping_sub(1) >= CUR_MAX_PX as u32 || hh.wrapping_sub(1) >= CUR_MAX_PX as u32 {
94 return None;
95 }
96 let mut sf = Surface::new(w as i32, hh as i32, FMT_PARGB);
97 if sf.px.is_empty() {
98 return None;
99 }
100 self.dc.begin(&sf);
101 {
102 let mut g = Gfx { dc: &mut self.dc, sf: &mut sf, text: &mut self.text };
103 (r.f)(&mut g, dpi);
104 }
105 self.dc.end();
106 Some(sf)
107 }
108
109 pub(crate) fn cursor_resolve(&mut self, shape: u32) -> u32 {
112 if shape != CUR_CUSTOM {
113 return shape;
114 }
115 let h = self.ucur.cur;
116 let Some(r) = self.uc_rec(h).cloned() else { return CUR_CROSS };
117 let dpi = plat::cursor_dpi(self.wp.rt.dpi) as u32; if r.dpi == dpi {
119 if r.plat >= 0 {
120 return r.plat as u32;
121 }
122 if r.plat == -2 {
123 return CUR_CROSS; }
125 }
126 if r.plat >= 0 {
128 plat::cursor_destroy(r.plat);
129 }
130 let i = (h - 1) as usize;
131 if let Some(s) = self.ucur.slots[i].as_mut() {
132 s.plat = -2;
133 s.dpi = dpi;
134 }
135 let Some(sf) = self.cursor_render(h, dpi as i32) else { return CUR_CROSS };
136 let (w, hh) = (sf.w as usize, sf.h as usize);
138 let mut px = Vec::with_capacity(w * hh * 4);
139 for y in 0..hh {
140 let o = y * sf.stride as usize;
141 px.extend_from_slice(&sf.px[o..o + w * 4]);
142 }
143 let hx = ((r.hot & 0xFFFF).wrapping_mul(dpi).wrapping_add(48) / 96) as i32;
145 let hy = ((r.hot >> 16).wrapping_mul(dpi).wrapping_add(48) / 96) as i32;
146 let id = plat::cursor_create(&px, w as i32, hh as i32, hx, hy, dpi as i32);
147 if id >= 0 {
148 if let Some(s) = self.ucur.slots[i].as_mut() {
149 s.plat = id;
150 }
151 return id as u32;
152 }
153 CUR_CROSS
154 }
155}