Skip to main content

atmos/apps/
canvas.rs

1// src/apps/canvas.rs - Canvas Application for Aura Drawing Commands
2#![allow(dead_code)]
3
4use crate::kernel::draw::{Color, Screen};
5use crate::kernel::window_mgr::App;
6use alloc::collections::BTreeMap;
7use alloc::collections::VecDeque;
8use alloc::string::String;
9use alloc::vec::Vec;
10use spin::Mutex;
11
12#[derive(Debug, Clone)]
13pub enum DrawCommand {
14    BoxFill {
15        x0: u32,
16        y0: u32,
17        x1: u32,
18        y1: u32,
19        color: u32,
20    },
21    DrawString {
22        x: u32,
23        y: u32,
24        text: String,
25        color: u32,
26        size: u32,
27    },
28    ClearScreen {
29        color: u32,
30    },
31}
32
33pub static CANVAS_QUEUES: Mutex<BTreeMap<String, VecDeque<DrawCommand>>> =
34    Mutex::new(BTreeMap::new());
35pub static CANVAS_ID_COUNTER: Mutex<u32> = Mutex::new(0);
36
37pub struct CanvasApp {
38    pub id: String,
39    pub title: String,
40    pub buffer: Vec<u32>,
41    pub width: u32,
42    pub height: u32,
43}
44
45impl CanvasApp {
46    pub fn new(id: String, title: String, width: u32, height: u32) -> Self {
47        Self {
48            id,
49            title,
50            buffer: alloc::vec![0xFFFFFFFF; (width * height) as usize], // Default background: white
51            width,
52            height,
53        }
54    }
55}
56
57impl App for CanvasApp {
58    fn name(&self) -> &str {
59        &self.title
60    }
61
62    fn draw(&mut self, screen: &Screen, win_x: u32, win_y: u32, win_w: u32, win_h: u32) {
63        // Handle resizing: expand/shrink buffer if window size changed
64        if win_w != self.width || win_h != self.height {
65            let mut new_buf = alloc::vec![0xFFFFFFFF; (win_w * win_h) as usize];
66            let min_w = self.width.min(win_w);
67            let min_h = self.height.min(win_h);
68            for y in 0..min_h {
69                let src_offset = (y * self.width) as usize;
70                let dst_offset = (y * win_w) as usize;
71                new_buf[dst_offset..dst_offset + min_w as usize]
72                    .copy_from_slice(&self.buffer[src_offset..src_offset + min_w as usize]);
73            }
74            self.buffer = new_buf;
75            self.width = win_w;
76            self.height = win_h;
77        }
78
79        // Retrieve drawing commands for this canvas
80        let mut cmds = VecDeque::new();
81        if let Some(q) = CANVAS_QUEUES.lock().get_mut(&self.id) {
82            cmds = core::mem::take(q);
83        }
84
85        // Apply commands to the backbuffer
86        if !cmds.is_empty() {
87            let temp_screen = Screen::new(
88                self.buffer.as_mut_ptr(),
89                self.width,
90                self.height,
91                self.width * 4,
92            );
93            for cmd in cmds {
94                match cmd {
95                    DrawCommand::BoxFill {
96                        x0,
97                        y0,
98                        x1,
99                        y1,
100                        color,
101                    } => {
102                        temp_screen.boxfill(x0, y0, x1, y1, Color(color));
103                    }
104                    DrawCommand::DrawString {
105                        x,
106                        y,
107                        text,
108                        color,
109                        size,
110                    } => {
111                        temp_screen.draw_string_vector(x, y, &text, Color(color), size);
112                    }
113                    DrawCommand::ClearScreen { color } => {
114                        temp_screen.boxfill(
115                            0,
116                            0,
117                            self.width.saturating_sub(1),
118                            self.height.saturating_sub(1),
119                            Color(color),
120                        );
121                    }
122                }
123            }
124        }
125
126        // Copy the backbuffer to the physical screen's client area (win_x, win_y)
127        let (target_ptr, dw, dh) = screen.resolve_target();
128        let stride = screen.resolve_stride();
129
130        let (cx0, cy0, cx1, cy1) = screen.clip.get().unwrap_or((0, 0, dw, dh));
131
132        let x0 = win_x.max(cx0).min(dw);
133        let y0 = win_y.max(cy0).min(dh);
134        let x1 = (win_x + win_w).min(cx1).min(dw);
135        let y1 = (win_y + win_h).min(cy1).min(dh);
136
137        if x1 > x0 && y1 > y0 {
138            let copy_w = x1 - x0;
139            for y in y0..y1 {
140                let src_y = y - win_y;
141                let src_x = x0 - win_x;
142                unsafe {
143                    let src_ptr = self.buffer.as_ptr().add((src_y * win_w + src_x) as usize);
144                    let dst_ptr = target_ptr.add((y * stride + x0) as usize);
145                    core::ptr::copy_nonoverlapping(src_ptr, dst_ptr, copy_w as usize);
146                }
147            }
148        }
149    }
150
151    fn on_mouse(
152        &mut self,
153        _local_x: i32,
154        _local_y: i32,
155        _btn_left: bool,
156        _btn_right: bool,
157        _wheel: i32,
158    ) {
159    }
160
161    fn on_key(&mut self, _keycode: u8, _pressed: bool, _ascii: Option<char>) {}
162}