|
1 | 1 | //! Screen-related commands for Neotron OS |
2 | 2 |
|
3 | | -use neotron_common_bios::video::{Attr, TextBackgroundColour, TextForegroundColour}; |
| 3 | +use crate::{osprint, Ctx}; |
4 | 4 |
|
5 | | -use crate::{osprint, osprintln, Ctx, API, VGA_CONSOLE}; |
6 | | - |
7 | | -pub static CLEAR_ITEM: menu::Item<Ctx> = menu::Item { |
| 5 | +pub static CLS_ITEM: menu::Item<Ctx> = menu::Item { |
8 | 6 | item_type: menu::ItemType::Callback { |
9 | | - function: clear, |
| 7 | + function: cls, |
10 | 8 | parameters: &[], |
11 | 9 | }, |
12 | | - command: "screen_clear", |
| 10 | + command: "cls", |
13 | 11 | help: Some("Clear the screen"), |
14 | 12 | }; |
15 | 13 |
|
16 | | -pub static FILL_ITEM: menu::Item<Ctx> = menu::Item { |
17 | | - item_type: menu::ItemType::Callback { |
18 | | - function: fill, |
19 | | - parameters: &[], |
20 | | - }, |
21 | | - command: "screen_fill", |
22 | | - help: Some("Fill the screen with characters"), |
23 | | -}; |
24 | | - |
25 | | -pub static BENCH_ITEM: menu::Item<Ctx> = menu::Item { |
26 | | - item_type: menu::ItemType::Callback { |
27 | | - function: bench, |
28 | | - parameters: &[], |
29 | | - }, |
30 | | - command: "screen_bench", |
31 | | - help: Some("Time how long to put 1,000,000 characters on the screen, with scrolling."), |
32 | | -}; |
33 | | - |
34 | | -pub static MANDEL_ITEM: menu::Item<Ctx> = menu::Item { |
35 | | - item_type: menu::ItemType::Callback { |
36 | | - function: mandel, |
37 | | - parameters: &[], |
38 | | - }, |
39 | | - command: "screen_mandel", |
40 | | - help: Some("Calculate the Mandelbrot set"), |
41 | | -}; |
42 | | - |
43 | | -/// Called when the "clear" command is executed. |
44 | | -fn clear(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], _ctx: &mut Ctx) { |
45 | | - let mut guard = VGA_CONSOLE.try_lock().unwrap(); |
46 | | - if let Some(vga_console) = guard.as_mut() { |
47 | | - vga_console.clear(); |
48 | | - } |
49 | | -} |
50 | | - |
51 | | -/// Called when the "fill" command is executed. |
52 | | -fn fill(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], _ctx: &mut Ctx) { |
53 | | - let mut guard = VGA_CONSOLE.try_lock().unwrap(); |
54 | | - if let Some(console) = guard.as_mut() { |
55 | | - console.clear(); |
56 | | - let api = API.get(); |
57 | | - let mode = (api.video_get_mode)(); |
58 | | - let (Some(width), Some(height)) = (mode.text_width(), mode.text_height()) else { |
59 | | - osprintln!("Unable to get console size"); |
60 | | - return; |
61 | | - }; |
62 | | - // A range of printable ASCII compatible characters |
63 | | - let mut char_cycle = (b' '..=b'~').cycle(); |
64 | | - let mut remaining = height * width; |
65 | | - |
66 | | - // Scroll two screen fulls |
67 | | - 'outer: for bg in (0..=7).cycle() { |
68 | | - let bg_colour = TextBackgroundColour::new(bg).unwrap(); |
69 | | - for fg in 1..=15 { |
70 | | - if fg == bg { |
71 | | - continue; |
72 | | - } |
73 | | - let fg_colour = TextForegroundColour::new(fg).unwrap(); |
74 | | - remaining -= 1; |
75 | | - if remaining == 0 { |
76 | | - break 'outer; |
77 | | - } |
78 | | - let attr = Attr::new(fg_colour, bg_colour, false); |
79 | | - let glyph = char_cycle.next().unwrap(); |
80 | | - console.set_attr(attr); |
81 | | - console.write_bstr(&[glyph]); |
82 | | - } |
83 | | - } |
84 | | - let attr = Attr::new( |
85 | | - TextForegroundColour::WHITE, |
86 | | - TextBackgroundColour::BLACK, |
87 | | - false, |
88 | | - ); |
89 | | - console.set_attr(attr); |
90 | | - } |
91 | | -} |
92 | | - |
93 | | -/// Called when the "bench" command is executed. |
94 | | -fn bench(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], _ctx: &mut Ctx) { |
95 | | - const NUM_CHARS: u64 = 1_000_000; |
96 | | - let mut guard = VGA_CONSOLE.try_lock().unwrap(); |
97 | | - if let Some(console) = guard.as_mut() { |
98 | | - let api = API.get(); |
99 | | - let start = (api.time_ticks_get)(); |
100 | | - console.clear(); |
101 | | - let glyphs = &[b'x']; |
102 | | - for _idx in 0..NUM_CHARS { |
103 | | - console.write_bstr(glyphs); |
104 | | - } |
105 | | - let end = (api.time_ticks_get)(); |
106 | | - let delta = end.0 - start.0; |
107 | | - let chars_per_second = (NUM_CHARS * (api.time_ticks_per_second)().0) / delta; |
108 | | - osprintln!( |
109 | | - "{} chars in {} ticks, or {} chars per second", |
110 | | - NUM_CHARS, |
111 | | - delta, |
112 | | - chars_per_second |
113 | | - ); |
114 | | - } |
115 | | -} |
116 | | - |
117 | | -/// Called when the "mandel" command is executed. |
118 | | -fn mandel(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], _ctx: &mut Ctx) { |
119 | | - fn mandelbrot(cx: f64, cy: f64, max_loops: u32) -> u32 { |
120 | | - let mut x = cx; |
121 | | - let mut y = cy; |
122 | | - for i in 1..max_loops { |
123 | | - let x_squared = x * x; |
124 | | - let y_squared = y * y; |
125 | | - if x_squared + y_squared > 4.0 { |
126 | | - return i; |
127 | | - } |
128 | | - let x1 = x_squared - y_squared + cx; |
129 | | - let y1 = (2.0 * x * y) + cy; |
130 | | - x = x1; |
131 | | - y = y1; |
132 | | - } |
133 | | - 0 |
134 | | - } |
135 | | - |
136 | | - let api = API.get(); |
137 | | - let mode = (api.video_get_mode)(); |
138 | | - let (Some(width), Some(height)) = (mode.text_width(), mode.text_height()) else { |
139 | | - osprintln!("Unable to get screen size"); |
140 | | - return; |
141 | | - }; |
142 | | - |
143 | | - let glyphs = b" .,'~!^:;[/<&?oxOX# "; |
144 | | - for y_pos in 0..height - 2 { |
145 | | - let y = (f64::from(y_pos) * 4.0 / f64::from(height)) - 2.0; |
146 | | - for x_pos in 0..width { |
147 | | - let x = (f64::from(x_pos) * 4.0 / f64::from(width)) - 2.0; |
148 | | - let result = mandelbrot(x, y, 20); |
149 | | - osprint!("{}", glyphs[result as usize] as char); |
150 | | - } |
151 | | - } |
| 14 | +/// Called when the "cls" command is executed. |
| 15 | +fn cls(_menu: &menu::Menu<Ctx>, _item: &menu::Item<Ctx>, _args: &[&str], _ctx: &mut Ctx) { |
| 16 | + // Reset SGR, go home, clear screen, |
| 17 | + let _ = osprint!("\u{001b}[0m\u{001b}[1;1H\u{001b}[2J"); |
152 | 18 | } |
0 commit comments