summaryrefslogtreecommitdiffstats
path: root/bins/paint
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-08-27 17:23:34 +0200
committersalmonik <salmonik@tuta.io>2026-08-27 17:23:34 +0200
commitba304898b8e177d90afb58d201b4c3dd3c927c48 (patch)
tree3bcca98cb09ed8c035218039d9c86401d8ea0066 /bins/paint
parenttool migration: v2 exports + 10 external CLI binaries (diff)
downloadrs-dos-ba304898b8e177d90afb58d201b4c3dd3c927c48.tar.gz
rs-dos-ba304898b8e177d90afb58d201b4c3dd3c927c48.zip
GUI: window/event exports, paint binary, event-loop gate
rsapi: WmEvent (kind=u8 enum: 0=key, 1=mouse, 2=focus, 3=close), WmKeyKind (Char/Enter/Backspace/F1-F4/…), WmMouseEvent (x/y/buttons), WindowInfo (ptr/w/h). Five new exports: wm_create, wm_buffer, wm_flush, wm_destroy, wm_recv (non-blocking TaskMsg dispatch → WmEvent). Shell: abi_wm_* wrappers bridge rsapi types to rsnix::wm and sched::recv(); wm_recv translates TaskMsg::Key/Mouse/Focus/Close into flat WmEvent union. bins/paint: gate binary — create_window + buffer + event loop with Bresenham line drawing, color select (1-8), clear (c), F4 close. All via wm_* ABI exports. Fully migrated: date, mem, pci, cat, ls, mkdir, touch, rm, klog, info, paint (11 external binaries in /bin/cli/ + 3 gate binaries).
Diffstat (limited to '')
-rw-r--r--bins/paint/Cargo.toml8
-rw-r--r--bins/paint/src/main.rs137
2 files changed, 145 insertions, 0 deletions
diff --git a/bins/paint/Cargo.toml b/bins/paint/Cargo.toml
new file mode 100644
index 0000000..c89597e
--- /dev/null
+++ b/bins/paint/Cargo.toml
@@ -0,0 +1,8 @@
1[package]
2name = "paint"
3version.workspace = true
4edition.workspace = true
5[lints]
6workspace = true
7[dependencies]
8rsapi = { path = "../../rsapi" }
diff --git a/bins/paint/src/main.rs b/bins/paint/src/main.rs
new file mode 100644
index 0000000..d395a4c
--- /dev/null
+++ b/bins/paint/src/main.rs
@@ -0,0 +1,137 @@
1//! paint — drawing canvas via the GUI exports table.
2//!
3//! Keys: 1-8 select color, c clears to black. Mouse draws when pressed.
4
5#![no_std]
6#![no_main]
7
8#[panic_handler]
9fn panic(_info: &core::panic::PanicInfo) -> ! {
10 loop { core::hint::spin_loop(); }
11}
12
13const W: u32 = 640;
14const H: u32 = 400;
15
16const fn pack(r: u8, g: u8, b: u8) -> u32 {
17 ((r as u32) << 16) | ((g as u32) << 8) | (b as u32)
18}
19
20const PALETTE: [u32; 9] = [
21 pack(255, 255, 255), // 1 white
22 pack(255, 0, 0), // 2 red
23 pack(0, 255, 0), // 3 green
24 pack(0, 0, 255), // 4 blue
25 pack(255, 255, 0), // 5 yellow
26 pack(255, 0, 255), // 6 magenta
27 pack(0, 255, 255), // 7 cyan
28 pack(255, 128, 0), // 8 orange
29 pack(0, 0, 0), // clear (black)
30];
31
32#[unsafe(no_mangle)]
33pub extern "C" fn efi_main(exports: &'static rsapi::Exports, _argc: usize, _argv: *const rsapi::Arg) -> i32 {
34 // Create window
35 let title = b"paint";
36 let win = (exports.wm_create)(rsapi::Line { ptr: title.as_ptr(), len: title.len() }, W, H);
37 if win < 0 { return 1; }
38
39 // Get pixel buffer
40 let mut info = rsapi::WindowInfo { ptr: core::ptr::null_mut(), w: 0, h: 0 };
41 if !(exports.wm_buffer)(win, &mut info) {
42 (exports.wm_destroy)(win);
43 return 1;
44 }
45
46 let buf = info.ptr;
47 let bw = info.w as usize;
48 let bh = info.h as usize;
49
50 let mut color: usize = 0;
51 let mut last_x: i32 = -1;
52 let mut last_y: i32 = -1;
53
54 let mut ev = rsapi::WmEvent {
55 kind: 0,
56 key_kind: rsapi::WmKeyKind::Char,
57 key_char: 0,
58 mouse: rsapi::WmMouseEvent { x: 0, y: 0, buttons: 0 },
59 focused: false,
60 _pad: [0; 4],
61 };
62
63 // Event loop
64 loop {
65 if !(exports.wm_recv)(&mut ev) {
66 continue;
67 }
68 match ev.kind {
69 0 => {
70 // Key event
71 match ev.key_kind {
72 rsapi::WmKeyKind::Char => {
73 match ev.key_char {
74 b'1'..=b'8' => color = (ev.key_char - b'1') as usize,
75 b'c' => {
76 unsafe {
77
78 let n = bw * bh;
79 let p = buf as *mut u32;
80 for i in 0..n {
81 *p.add(i) = 0;
82 }
83 }
84 (exports.wm_flush)(win);
85 }
86 _ => {}
87 }
88 }
89 rsapi::WmKeyKind::F4 => break,
90 _ => {}
91 }
92 }
93 1 => {
94 // Mouse event
95 let m = &ev.mouse;
96 if m.buttons & 1 != 0 {
97 // Left button: draw pixel at (m.x, m.y)
98 if m.x >= 0 && m.y >= 0 && (m.x as usize) < bw && (m.y as usize) < bh {
99 unsafe {
100
101 *buf.add(m.y as usize * bw + m.x as usize) = PALETTE[color % PALETTE.len()];
102 }
103 // Connect with last point (line drawing)
104 if last_x >= 0 {
105 let lx = last_x; let ly = last_y;
106 let dx = (m.x - lx).abs(); let sx = if lx < m.x { 1 } else { -1 };
107 let dy = -(m.y - ly).abs(); let sy = if ly < m.y { 1 } else { -1 };
108 let mut err = dx + dy;
109 let mut cx = lx; let mut cy = ly;
110 loop {
111 if cx >= 0 && cy >= 0 && (cx as usize) < bw && (cy as usize) < bh {
112 unsafe {
113 *buf.add(cy as usize * bw + cx as usize) = PALETTE[color % PALETTE.len()]; }
114 }
115 if cx == m.x && cy == m.y { break; }
116 let e2 = 2 * err;
117 if e2 >= dy { err += dy; cx += sx; }
118 if e2 <= dx { err += dx; cy += sy; }
119 }
120 }
121 (exports.wm_flush)(win);
122 last_x = m.x;
123 last_y = m.y;
124 }
125 } else {
126 last_x = -1; last_y = -1;
127 }
128 }
129 2 => {} // focus
130 3 => break, // close
131 _ => {}
132 }
133 }
134
135 (exports.wm_destroy)(win);
136 0
137}