cardinal_gui/
stage.rs

1use crate::cardinal_orcas_symbols::cardinal_orcas_symbols::get_slice; 
2
3impl<'a> Stage<'a> {
4    /// Load symbols from a byte slice (for embedded .sym files)
5    pub fn load_symbols(&mut self, data: &[u8]) {
6        if let Ok(map) = varvara::Varvara::parse_symbols_from_bytes(data) {
7            self.dev.symbols = Some(map);
8        }
9    }
10    /// Load a ROM from a file path and attempt to load a .sys symbol file if present
11    pub fn load_rom_with_path<P: AsRef<std::path::Path>>(&mut self, path: P) {
12        let path = path.as_ref();
13        if let Ok(data) = std::fs::read(path) {
14            let _ = self.vm.reset(&data);
15            self.dev.reset(&data);
16            self.vm.run(&mut self.dev, 0x100);
17            let out = self.dev.output(&self.vm);
18            self.size = out.size;
19            // Look for a .sys file with the same file name as the ROM, e.g. orca.rom -> orca.rom.sys
20            if let Some(file_name) = path.file_name() {
21                use std::ffi::OsString;
22                use std::path::PathBuf;
23                let mut sys_file = OsString::from(file_name);
24                sys_file.push(".sym");
25                let mut sys_path = PathBuf::from(path);
26                sys_path.set_file_name(sys_file);
27                #[cfg(windows)]
28                let mut sys_path_str = sys_path.to_string_lossy().to_string();
29                #[cfg(windows)]
30                {
31                    sys_path_str = sys_path_str.replace("/", "\\");
32                }
33                #[cfg(not(windows))]
34                let sys_path_str = sys_path.to_string_lossy().to_string();
35                println!(
36                    "[DEBUG][Stage] Attempting to load symbols from {sys_path_str}");
37                if sys_path.exists() {
38                    let _ = self.dev.load_symbols_into_self(&sys_path_str);
39                    println!(
40                        "[DEBUG][Stage] Loaded symbols from {sys_path_str}"
41                    );
42                }
43            }
44        }
45    }
46
47    /// Handle mouse events only (for hover)
48    pub fn handle_mouse_input(
49        &mut self,
50        input: &egui::InputState,
51        _response: &egui::Response,
52        rect: egui::Rect,
53    ) {
54        if let Some(mouse_pos) = input.pointer.hover_pos() {
55            if rect.contains(mouse_pos) {
56                let rel_x =
57                    (mouse_pos.x - rect.min.x).max(0.0).min(rect.width());
58                let rel_y =
59                    (mouse_pos.y - rect.min.y).max(0.0).min(rect.height());
60                let mut buttons = 0u8;
61                if input.pointer.button_down(egui::PointerButton::Primary) {
62                    buttons |= 1;
63                }
64                if input.pointer.button_down(egui::PointerButton::Middle) {
65                    buttons |= 2;
66                }
67                if input.pointer.button_down(egui::PointerButton::Secondary) {
68                    buttons |= 4;
69                }
70                let mouse_state = varvara::MouseState {
71                    pos: (rel_x, rel_y),
72                    scroll: (0.0, 0.0),
73                    buttons,
74                };
75                self.dev.mouse(&mut self.vm, mouse_state);
76            }
77        }
78        // Also handle pointer button events
79        for event in &input.events {
80            if let egui::Event::PointerButton {
81                pos,
82                button,
83                pressed,
84                ..
85            } = event
86            {
87                if rect.contains(*pos) {
88                    let rel_x = (pos.x - rect.min.x).max(0.0).min(rect.width());
89                    let rel_y =
90                        (pos.y - rect.min.y).max(0.0).min(rect.height());
91                    let mut buttons = 0u8;
92                    if *button == egui::PointerButton::Primary && *pressed {
93                        buttons |= 1;
94                    }
95                    if *button == egui::PointerButton::Middle && *pressed {
96                        buttons |= 2;
97                    }
98                    if *button == egui::PointerButton::Secondary && *pressed {
99                        buttons |= 4;
100                    }
101                    let mouse_state = varvara::MouseState {
102                        pos: (rel_x, rel_y),
103                        scroll: (0.0, 0.0),
104                        buttons,
105                    };
106                    self.dev.mouse(&mut self.vm, mouse_state);
107                }
108            }
109        }
110    }
111
112    /// Handle keyboard events only (for focus)
113    pub fn handle_keyboard_input(&mut self, input: &egui::InputState) {
114        for event in &input.events {
115            if let egui::Event::Key { key, pressed, .. } = event {
116                if let Some(varvara_key) = map_egui_key_to_varvara_key(*key) {
117                    println!("[DEBUG][Stage] Forwarding key: {key:?} pressed={pressed} to VM as {varvara_key:?}");
118                    if *pressed {
119                        self.dev.pressed(&mut self.vm, varvara_key, false);
120                    } else {
121                        self.dev.released(&mut self.vm, varvara_key);
122                    }
123                } else {
124                    println!("[DEBUG][Stage] Ignored key: {key:?}");
125                }
126            }
127        }
128    }
129
130    /// Draw mesh at a specific rect (used by UxnPanel)
131    pub fn draw_at(&self, ui: &mut egui::Ui, rect: egui::Rect) {
132        let panel_size =
133            egui::Vec2::new(self.size.0 as f32, self.size.1 as f32)
134                * self.scale;
135        let mut mesh = egui::Mesh::with_texture(self.texture.id());
136        mesh.add_rect_with_uv(
137            egui::Rect {
138                min: rect.min,
139                max: rect.min + panel_size,
140            },
141            egui::Rect {
142                min: egui::Pos2::new(0.0, 0.0),
143                max: egui::Pos2::new(1.0, 1.0),
144            },
145            egui::Color32::WHITE,
146        );
147        ui.painter().add(egui::Shape::mesh(mesh));
148    }
149
150    /// Handle egui input events and forward to VM/device
151    pub fn handle_input(
152        &mut self,
153        input: &egui::InputState,
154        _response: &egui::Response,
155        rect: egui::Rect,
156    ) {
157        // Forward text events as char events to the VM/device (for printable chars)
158        for event in &input.events {
159            if let egui::Event::Text(s) = event {
160                for c in s.chars() {
161                    // Only send printable ASCII (or adjust as needed for your ROM)
162                    if c.is_ascii_graphic() || c == ' ' {
163                        let byte = c as u8;
164                        println!("[DEBUG][Stage] Forwarding char event: '{c}' (0x{byte:02x}) to VM (from egui::Event::Text)");
165                        self.dev.pressed(
166                            &mut self.vm,
167                            varvara::Key::Char(byte),
168                            false,
169                        );
170                        self.dev.char(&mut self.vm, byte);
171                    } else {
172                        println!("[DEBUG][Stage] Ignored char event: '{}' (0x{:02x}) (not printable)", c, c as u8);
173                    }
174                }
175            }
176        }
177        // Only send key events for non-printable keys (arrows, enter, etc)
178        use egui::Key;
179        for event in &input.events {
180            if let egui::Event::Key { key, pressed, .. } = event {
181                let is_printable = matches!(
182                    key,
183                    Key::A
184                        | Key::B
185                        | Key::C
186                        | Key::D
187                        | Key::E
188                        | Key::F
189                        | Key::G
190                        | Key::H
191                        | Key::I
192                        | Key::J
193                        | Key::K
194                        | Key::L
195                        | Key::M
196                        | Key::N
197                        | Key::O
198                        | Key::P
199                        | Key::Q
200                        | Key::R
201                        | Key::S
202                        | Key::T
203                        | Key::U
204                        | Key::V
205                        | Key::W
206                        | Key::X
207                        | Key::Y
208                        | Key::Z
209                        | Key::Num0
210                        | Key::Num1
211                        | Key::Num2
212                        | Key::Num3
213                        | Key::Num4
214                        | Key::Num5
215                        | Key::Num6
216                        | Key::Num7
217                        | Key::Num8
218                        | Key::Num9
219                        | Key::Space
220                        | Key::Tab
221                        | Key::Backtick
222                        | Key::Backslash
223                        | Key::Pipe
224                        | Key::Comma
225                        | Key::Equals
226                        | Key::Plus
227                        | Key::OpenBracket
228                        | Key::Minus
229                        | Key::Period
230                        | Key::CloseBracket
231                        | Key::Semicolon
232                        | Key::Colon
233                        | Key::Slash
234                        | Key::Questionmark
235                );
236                if !is_printable {
237                    if let Some(varvara_key) = map_egui_key_to_varvara_key(*key)
238                    {
239                        println!("[DEBUG][Stage] Forwarding non-printable key: {key:?} pressed={pressed} to VM as {varvara_key:?}");
240                        if *pressed {
241                            self.dev.pressed(&mut self.vm, varvara_key, false);
242                        } else {
243                            self.dev.released(&mut self.vm, varvara_key);
244                        }
245                    } else {
246                        println!("[DEBUG][Stage] Ignored key: {key:?}");
247                    }
248                }
249            }
250        }
251        // Forward mouse position and button state
252        if let Some(mouse_pos) = input.pointer.hover_pos() {
253            if rect.contains(mouse_pos) {
254                let rel_x =
255                    (mouse_pos.x - rect.min.x).max(0.0).min(rect.width());
256                let rel_y =
257                    (mouse_pos.y - rect.min.y).max(0.0).min(rect.height());
258                let mut buttons = 0u8;
259                if input.pointer.button_down(egui::PointerButton::Primary) {
260                    buttons |= 1;
261                }
262                if input.pointer.button_down(egui::PointerButton::Middle) {
263                    buttons |= 2;
264                }
265                if input.pointer.button_down(egui::PointerButton::Secondary) {
266                    buttons |= 4;
267                }
268                let mouse_state = varvara::MouseState {
269                    pos: (rel_x, rel_y),
270                    scroll: (0.0, 0.0),
271                    buttons,
272                };
273                self.dev.mouse(&mut self.vm, mouse_state);
274            }
275        }
276        // Forward pointer button events (for clicks)
277        for event in &input.events {
278            if let egui::Event::PointerButton {
279                pos,
280                button,
281                pressed,
282                ..
283            } = event
284            {
285                if rect.contains(*pos) {
286                    let rel_x = (pos.x - rect.min.x).max(0.0).min(rect.width());
287                    let rel_y =
288                        (pos.y - rect.min.y).max(0.0).min(rect.height());
289                    let mut buttons = 0u8;
290                    if *button == egui::PointerButton::Primary && *pressed {
291                        buttons |= 1;
292                    }
293                    if *button == egui::PointerButton::Middle && *pressed {
294                        buttons |= 2;
295                    }
296                    if *button == egui::PointerButton::Secondary && *pressed {
297                        buttons |= 4;
298                    }
299                    let mouse_state = varvara::MouseState {
300                        pos: (rel_x, rel_y),
301                        scroll: (0.0, 0.0),
302                        buttons,
303                    };
304                    println!("[DEBUG][Stage] Forwarding pointer button: {button:?} pressed={pressed} at rel=({rel_x:.1},{rel_y:.1})");
305                    self.dev.mouse(&mut self.vm, mouse_state);
306                }
307            }
308        }
309    }
310}
311
312// Helper: Map egui::Key to Varvara::Key (basic ASCII)
313fn map_egui_key_to_varvara_key(key: egui::Key) -> Option<varvara::Key> {
314    use egui::Key;
315    use varvara::Key as VKey;
316    Some(match key {
317        Key::ArrowUp => VKey::Up,
318        Key::ArrowDown => VKey::Down,
319        Key::ArrowLeft => VKey::Left,
320        Key::ArrowRight => VKey::Right,
321        Key::Home => VKey::Home,
322        Key::End => VKey::End,
323        Key::Tab => VKey::Char(b'\t'),
324        Key::Backspace => VKey::Char(8),
325        Key::Enter => VKey::Char(b'\n'),
326        Key::Space => VKey::Char(b' '),
327        Key::A => VKey::Char(b'a'),
328        Key::B => VKey::Char(b'b'),
329        Key::C => VKey::Char(b'c'),
330        Key::D => VKey::Char(b'd'),
331        Key::E => VKey::Char(b'e'),
332        Key::F => VKey::Char(b'f'),
333        Key::G => VKey::Char(b'g'),
334        Key::H => VKey::Char(b'h'),
335        Key::I => VKey::Char(b'i'),
336        Key::J => VKey::Char(b'j'),
337        Key::K => VKey::Char(b'k'),
338        Key::L => VKey::Char(b'l'),
339        Key::M => VKey::Char(b'm'),
340        Key::N => VKey::Char(b'n'),
341        Key::O => VKey::Char(b'o'),
342        Key::P => VKey::Char(b'p'),
343        Key::Q => VKey::Char(b'q'),
344        Key::R => VKey::Char(b'r'),
345        Key::S => VKey::Char(b's'),
346        Key::T => VKey::Char(b't'),
347        Key::U => VKey::Char(b'u'),
348        Key::V => VKey::Char(b'v'),
349        Key::W => VKey::Char(b'w'),
350        Key::X => VKey::Char(b'x'),
351        Key::Y => VKey::Char(b'y'),
352        Key::Z => VKey::Char(b'z'),
353        Key::Num0 => VKey::Char(b'0'),
354        Key::Num1 => VKey::Char(b'1'),
355        Key::Num2 => VKey::Char(b'2'),
356        Key::Num3 => VKey::Char(b'3'),
357        Key::Num4 => VKey::Char(b'4'),
358        Key::Num5 => VKey::Char(b'5'),
359        Key::Num6 => VKey::Char(b'6'),
360        Key::Num7 => VKey::Char(b'7'),
361        Key::Num8 => VKey::Char(b'8'),
362        Key::Num9 => VKey::Char(b'9'),
363        _ => return None,
364    })
365}
366use eframe::egui;
367use std::sync::mpsc;
368use uxn::Uxn;
369use varvara::Varvara;
370
371#[derive(Debug)]
372pub enum Event {
373    LoadRom(Vec<u8>),
374    SetMuted(bool),
375    Console(u8),
376}
377
378pub struct Stage<'a> {
379    pub vm: Uxn<'a>,
380    pub dev: Varvara,
381    pub scale: f32,
382    pub size: (u16, u16),
383    pub next_frame: f64,
384    pub scroll: (f32, f32),
385    pub cursor_pos: Option<(f32, f32)>,
386    pub texture: egui::TextureHandle,
387    pub event_rx: mpsc::Receiver<Event>,
388    pub resized: Option<Box<dyn FnMut(u16, u16)>>,
389}
390
391impl<'a> Stage<'a> {
392    pub fn new(
393        vm: Uxn<'a>,
394        dev: Varvara,
395        size: (u16, u16),
396        scale: f32,
397        event_rx: mpsc::Receiver<Event>,
398        ctx: &egui::Context,
399        texture_name: String,
400    ) -> Self {
401        let image = egui::ColorImage::new(
402            [usize::from(size.0), usize::from(size.1)],
403            vec![egui::Color32::BLACK; (size.0 as usize) * (size.1 as usize)],
404        );
405        let texture = ctx.load_texture(
406            &texture_name,
407            image,
408            egui::TextureOptions::NEAREST,
409        );
410        Stage {
411            vm,
412            dev,
413            scale,
414            size,
415            next_frame: 0.0,
416            event_rx,
417            resized: None,
418            scroll: (0.0, 0.0),
419            cursor_pos: None,
420            texture,
421        }
422    }
423
424    pub fn get_bang(&self) {
425       get_slice(self.vm.ram,"*");
426    }
427
428    pub fn set_resize_callback(&mut self, f: Box<dyn FnMut(u16, u16)>) {
429        self.resized = Some(f);
430    }
431    pub fn load_rom(&mut self, data: &[u8]) {
432        let _ = self.vm.reset(data);
433        self.dev.reset(data);
434        self.vm.run(&mut self.dev, 0x100);
435        let out = self.dev.output(&self.vm);
436        self.size = out.size;
437    }
438    pub fn step(&mut self) {
439        // self.vm.run(&mut self.dev, 0x100);
440        self.dev.redraw(&mut self.vm);
441    }
442    pub fn update_texture(&mut self) {
443        let out = self.dev.output(&self.vm);
444        let mut image = egui::ColorImage::new(
445            [out.size.0 as usize, out.size.1 as usize],
446            vec![
447                egui::Color32::BLACK;
448                (out.size.0 as usize) * (out.size.1 as usize)
449            ],
450        );
451        for (i, o) in out.frame.chunks(4).zip(image.pixels.iter_mut()) {
452            *o = egui::Color32::from_rgba_unmultiplied(i[0], i[1], i[2], i[3]);
453        }
454        self.texture.set(image, egui::TextureOptions::NEAREST);
455    }
456    pub fn draw(&self, ui: &mut egui::Ui) {
457        let panel_size =
458            egui::Vec2::new(self.size.0 as f32, self.size.1 as f32)
459                * self.scale;
460        let (_rect_id, rect) = ui.allocate_space(panel_size);
461        let mut mesh = egui::Mesh::with_texture(self.texture.id());
462        mesh.add_rect_with_uv(
463            egui::Rect {
464                min: rect.min,
465                max: rect.min + panel_size,
466            },
467            egui::Rect {
468                min: egui::Pos2::new(0.0, 0.0),
469                max: egui::Pos2::new(1.0, 1.0),
470            },
471            egui::Color32::WHITE,
472        );
473        ui.painter().add(egui::Shape::mesh(mesh));
474    }
475
476    pub fn handle_usb_input(&mut self) {
477        if let Some(controller_usb) = self.dev.controller_usb_mut() {
478            let events =
479                varvara::controller_usb::ControllerPollEvents::poll_usb_events(
480                    controller_usb,
481                    &mut self.vm,
482                );
483            for event in events {
484                self.dev.process_event(&mut self.vm, event);
485            }
486        }
487        // let k = varvara::Key::Right;
488        // let repeat = false;
489        // self.dev.pressed(&mut self.vm, k, repeat);
490        // self.dev.released(&mut self.vm, k);
491        // let k = varvara::Key::Char(b'A');
492        //  self.dev
493        //      .pressed(&mut self.vm, varvara::Key::Char(b'a'), false);
494        // self.dev.char(&mut self.vm, b'a');
495    }
496}