1use super::types::PixelFormat;
8use crate::framebuffer::{CanvasBuffer, RgbColor};
9
10pub(crate) const CURSOR_W: usize = 12;
16pub(crate) const CURSOR_H: usize = 16;
18pub(crate) const TEXT_CURSOR_MAX_DIM: usize = 32;
20
21#[rustfmt::skip]
23pub(crate) const CURSOR_PIXELS: [u8; CURSOR_W * CURSOR_H] = [
24 1,0,0,0,0,0,0,0,0,0,0,0,
25 1,1,0,0,0,0,0,0,0,0,0,0,
26 1,2,1,0,0,0,0,0,0,0,0,0,
27 1,2,2,1,0,0,0,0,0,0,0,0,
28 1,2,2,2,1,0,0,0,0,0,0,0,
29 1,2,2,2,2,1,0,0,0,0,0,0,
30 1,2,2,2,2,2,1,0,0,0,0,0,
31 1,2,2,2,2,2,2,1,0,0,0,0,
32 1,2,2,2,2,2,2,2,1,0,0,0,
33 1,2,2,2,2,2,1,1,0,0,0,0,
34 1,2,2,2,1,0,0,0,0,0,0,0,
35 1,2,1,1,2,2,1,0,0,0,0,0,
36 1,1,0,0,1,2,2,1,0,0,0,0,
37 0,0,0,0,0,1,2,1,0,0,0,0,
38 0,0,0,0,0,0,1,1,0,0,0,0,
39 0,0,0,0,0,0,0,0,0,0,0,0,
40];
41
42pub(crate) struct CursorManager {
52 pub mc_x: i32,
54 pub mc_y: i32,
55 pub mc_visible: bool,
56 pub mc_save: [u32; CURSOR_W * CURSOR_H],
57
58 pub tc_col: usize,
60 pub tc_row: usize,
61 pub tc_w: usize,
62 pub tc_h: usize,
63 pub tc_visible: bool,
64 pub tc_color: u32,
65 pub tc_save: [u32; TEXT_CURSOR_MAX_DIM * TEXT_CURSOR_MAX_DIM],
66}
67
68impl CursorManager {
69 pub const fn new() -> Self {
71 Self {
72 mc_x: 0,
73 mc_y: 0,
74 mc_visible: false,
75 mc_save: [0u32; CURSOR_W * CURSOR_H],
76 tc_col: 0,
77 tc_row: 0,
78 tc_w: 0,
79 tc_h: 0,
80 tc_visible: false,
81 tc_color: 0,
82 tc_save: [0u32; TEXT_CURSOR_MAX_DIM * TEXT_CURSOR_MAX_DIM],
83 }
84 }
85
86 pub fn mc_save_hw(&mut self, canvas: &CanvasBuffer) {
92 let x = self.mc_x;
93 let y = self.mc_y;
94 for cy in 0..CURSOR_H {
95 for cx in 0..CURSOR_W {
96 let px = x + cx as i32;
97 let py = y + cy as i32;
98 if px < 0 || py < 0 || px as usize >= canvas.width || py as usize >= canvas.height {
99 self.mc_save[cy * CURSOR_W + cx] = 0;
100 continue;
101 }
102 self.mc_save[cy * CURSOR_W + cx] = canvas.read_hw_pixel(px as usize, py as usize);
103 }
104 }
105 }
106
107 pub fn mc_draw_hw(&mut self, canvas: &mut CanvasBuffer, fmt: &PixelFormat) {
109 let x = self.mc_x;
110 let y = self.mc_y;
111 let black = fmt.pack_rgb(RgbColor::BLACK.r, RgbColor::BLACK.g, RgbColor::BLACK.b);
112 let white = fmt.pack_rgb(RgbColor::WHITE.r, RgbColor::WHITE.g, RgbColor::WHITE.b);
113 for cy in 0..CURSOR_H {
114 for cx in 0..CURSOR_W {
115 let p = CURSOR_PIXELS[cy * CURSOR_W + cx];
116 if p == 0 {
117 continue;
118 }
119 let px = x + cx as i32;
120 let py = y + cy as i32;
121 if px < 0 || py < 0 || px as usize >= canvas.width || py as usize >= canvas.height {
122 continue;
123 }
124 let color = if p == 1 { black } else { white };
125 canvas.write_hw_pixel(px as usize, py as usize, color);
126 }
127 }
128 }
129
130 pub fn mc_erase_hw(&mut self, canvas: &mut CanvasBuffer) {
132 let x = self.mc_x;
133 let y = self.mc_y;
134 for cy in 0..CURSOR_H {
135 for cx in 0..CURSOR_W {
136 if CURSOR_PIXELS[cy * CURSOR_W + cx] == 0 {
137 continue;
138 }
139 let px = x + cx as i32;
140 let py = y + cy as i32;
141 if px < 0 || py < 0 || px as usize >= canvas.width || py as usize >= canvas.height {
142 continue;
143 }
144 canvas.write_hw_pixel(px as usize, py as usize, self.mc_save[cy * CURSOR_W + cx]);
145 }
146 }
147 }
148
149 pub fn update_mouse_cursor(
151 &mut self,
152 x: i32,
153 y: i32,
154 canvas: &mut CanvasBuffer,
155 fmt: &PixelFormat,
156 ) -> bool {
157 let moved = self.mc_visible && (self.mc_x != x || self.mc_y != y);
158 let needs_redraw = !self.mc_visible || moved;
159
160 if moved {
161 self.mc_erase_hw(canvas);
162 }
163 if needs_redraw {
164 self.mc_x = x;
165 self.mc_y = y;
166 self.mc_save_hw(canvas);
167 self.mc_draw_hw(canvas, fmt);
168 self.mc_visible = true;
169 }
170 needs_redraw
171 }
172
173 pub fn hide_mouse_cursor(&mut self, canvas: &mut CanvasBuffer) {
175 if self.mc_visible {
176 self.mc_erase_hw(canvas);
177 self.mc_visible = false;
178 }
179 }
180
181 pub fn text_cursor_rect(
187 &self,
188 col: usize,
189 row: usize,
190 glyph_w: usize,
191 glyph_h: usize,
192 ) -> (usize, usize, usize, usize) {
193 let tw = glyph_w.min(TEXT_CURSOR_MAX_DIM);
194 let th = glyph_h.min(TEXT_CURSOR_MAX_DIM);
195 (col * glyph_w, row * glyph_h, tw, th)
196 }
197
198 pub fn text_cursor_save_hw(
200 &mut self,
201 col: usize,
202 row: usize,
203 glyph_w: usize,
204 glyph_h: usize,
205 canvas: &CanvasBuffer,
206 ) {
207 let (tx, ty, tw, th) = self.text_cursor_rect(col, row, glyph_w, glyph_h);
208 for dy in 0..th {
209 for dx in 0..tw {
210 let px = tx + dx;
211 let py = ty + dy;
212 if px < canvas.width && py < canvas.height {
213 self.tc_save[dy * tw + dx] = canvas.read_hw_pixel(px, py);
214 }
215 }
216 }
217 }
218
219 pub fn text_cursor_draw_hw(
221 &mut self,
222 col: usize,
223 row: usize,
224 glyph_w: usize,
225 glyph_h: usize,
226 color: u32,
227 canvas: &mut CanvasBuffer,
228 ) {
229 let (tx, ty, tw, th) = self.text_cursor_rect(col, row, glyph_w, glyph_h);
230 for dy in 0..th {
231 for dx in 0..tw {
232 let px = tx + dx;
233 let py = ty + dy;
234 if px < canvas.width && py < canvas.height {
235 canvas.write_hw_pixel(px, py, color);
236 }
237 }
238 }
239 }
240
241 pub fn text_cursor_erase_hw(
243 &mut self,
244 col: usize,
245 row: usize,
246 glyph_w: usize,
247 glyph_h: usize,
248 canvas: &mut CanvasBuffer,
249 ) {
250 let (tx, ty, tw, th) = self.text_cursor_rect(col, row, glyph_w, glyph_h);
251 for dy in 0..th {
252 for dx in 0..tw {
253 let px = tx + dx;
254 let py = ty + dy;
255 if px < canvas.width && py < canvas.height {
256 canvas.write_hw_pixel(px, py, self.tc_save[dy * tw + dx]);
257 }
258 }
259 }
260 }
261
262 pub fn draw_text_cursor_overlay(
264 &mut self,
265 col: usize,
266 row: usize,
267 glyph_w: usize,
268 glyph_h: usize,
269 color: u32,
270 canvas: &mut CanvasBuffer,
271 ) {
272 self.text_cursor_draw_hw(col, row, glyph_w, glyph_h, color, canvas);
273 }
274
275 pub fn hide_text_cursor(
277 &mut self,
278 col: usize,
279 row: usize,
280 glyph_w: usize,
281 glyph_h: usize,
282 canvas: &mut CanvasBuffer,
283 ) {
284 if self.tc_visible {
285 self.text_cursor_erase_hw(col, row, glyph_w, glyph_h, canvas);
286 self.tc_visible = false;
287 }
288 }
289}