#![no_std] //! Paint — the first GUI app: a freehand pen on a raster canvas. use rsnix::ps2::{KeyEvent, MouseKind}; use rsnix::{sched, wm}; const W: usize = 640; const H: usize = 480; /// 8-colour palette selected by keys 1–8. const PALETTE: [(u8, u8, u8); 8] = [ (255, 255, 255), // 1 white (0, 0, 0), // 2 black (170, 0, 0), // 3 red (0, 170, 0), // 4 green (0, 0, 170), // 5 blue (170, 170, 0), // 6 yellow (0, 170, 170), // 7 cyan (170, 0, 170), // 8 magenta ]; /// Run the paint program as a spawned task: create a window, then loop on /// events (pen strokes from the mouse, colour/clear from keys) until `Close`. pub fn run() { let Some(id) = wm::create_window("paint", W, H) else { return; }; let Some((buf, _, _)) = wm::buffer(id) else { return; }; let mut color: usize = 0; // white let mut last: Option<(i32, i32)> = None; loop { match sched::recv_blocking() { sched::TaskMsg::Close => break, sched::TaskMsg::AppMouse(m) => match m.kind { MouseKind::Press => { plot(buf, m.x, m.y, color); last = Some((m.x, m.y)); wm::flush(id); } MouseKind::Move => { if m.buttons & 1 != 0 { if let Some((lx, ly)) = last { line(buf, lx, ly, m.x, m.y, color); wm::flush(id); } } last = Some((m.x, m.y)); } MouseKind::Release => { last = None; } }, sched::TaskMsg::Key(k) => { if let KeyEvent::Char(c) = k { match c { '1'..='8' => color = (c as u8 - b'1') as usize, 'c' => { fill(buf, 1); // clear to black wm::flush(id); } _ => {} } } } _ => {} } } wm::destroy(id); } fn pack(idx: usize) -> u32 { let (r, g, b) = PALETTE[idx.min(PALETTE.len() - 1)]; rsnix::gop::rgb(r, g, b) } fn plot(buf: *mut u32, x: i32, y: i32, color: usize) { if x < 0 || y < 0 || x >= W as i32 || y >= H as i32 { return; } unsafe { *buf.add(y as usize * W + x as usize) = pack(color); } } /// Bresenham line between two points. fn line(buf: *mut u32, x0: i32, y0: i32, x1: i32, y1: i32, color: usize) { let mut x = x0; let mut y = y0; let dx = (x1 - x0).abs(); let sx = if x0 < x1 { 1 } else { -1 }; let dy = -(y1 - y0).abs(); let sy = if y0 < y1 { 1 } else { -1 }; let mut err = dx + dy; loop { plot(buf, x, y, color); if x == x1 && y == y1 { break; } let e2 = 2 * err; if e2 >= dy { err += dy; x += sx; } if e2 <= dx { err += dx; y += sy; } } } fn fill(buf: *mut u32, color: usize) { unsafe { for i in 0..(W * H) { *buf.add(i) = pack(color); } } }