1mod window;
6use std::io::Write;
7use termion::color;
8use termion::screen::IntoAlternateScreen;
9use termion::terminal_size;
10use window::{Priority, Window};
11
12const MAX_WIN: usize = 6;
13const INIT: Option<Window> = None;
14const MAX_WIDTH: usize = 512;
15const MAX_HEIGHT: usize = 254;
16
17#[cfg(test)]
18mod screen_tests {
19 use super::*;
20 #[test]
21 fn create_screen() {
22 let mut screen = Screen::new();
23 let id_1 = screen.append_left_child(0).unwrap();
24 let id_2 = screen.append_down_child(0).unwrap();
25 screen.println(id_1, "Hello World").unwrap();
26 screen.println(id_2, "Hello World").unwrap();
27 }
28 #[test]
29 fn bridge_creation() {
30 let mut screen = Screen::name_screen("My New Screen");
31 screen.set_name("Change the name");
32 screen.set_window_name(0, "My only window").unwrap();
33 let bridge = Bridge::new(screen);
34 bridge.println(0, "Hello World").unwrap();
35 }
36 #[test]
37 fn not_found(){
38 let mut screen = Screen::new();
39 let err = screen.flush(3);
40 assert_eq!(Err(std::io::ErrorKind::NotFound), err);
41 }
42 #[test]
43 fn alredy_exists(){
44 let mut screen = Screen::new();
45 screen.append_left_child(0).unwrap();
46 let err = screen.append_left_child(0);
47 assert_eq!(Err(std::io::ErrorKind::AlreadyExists), err);
48 }
49 #[test]
50 fn out_of_memory(){
51 let mut screen = Screen::new();
52 let mut id:usize = 0;
53 for _ in 0..(MAX_WIN - 1) {
54 id = screen.append_left_child(id).unwrap();
55 }
56 let err = screen.append_left_child(0);
57 assert_eq!(Err(std::io::ErrorKind::OutOfMemory), err);
58 }
59}
60
61#[derive(Debug)]
62pub struct Screen {
65 name: String,
66 windows: [Option<Window>; MAX_WIN],
67 count: usize,
68 buffer: [[(u8, bool); MAX_WIDTH]; MAX_HEIGHT],
69}
70
71impl Screen {
72 pub fn new() -> Screen {
74 let mut screen = Screen {
75 windows: [INIT; MAX_WIN],
76 count: 1,
77 name: "Screen".to_string(),
78 buffer: [[(b' ', false); MAX_WIDTH]; MAX_HEIGHT],
79 };
80 screen.windows[0] = Some(Window::new(0));
81 screen.load();
82 screen
83 }
84 pub fn name_screen(name: &str) -> Screen {
86 let mut screen = Screen::new();
87 screen.set_name(name);
88 screen
89 }
90 pub fn set_name(&mut self, name: &str) {
92 self.name = name.to_string();
93 }
94 pub fn set_window_name(&mut self, id: usize, name: &str) -> Result<(), std::io::ErrorKind> {
96 self.validate_id(id)?;
97 self.windows[id].as_mut().unwrap().name = name.to_string();
98 Ok(())
99 }
100 fn load(&mut self) {
101 let mut scr = std::io::stdout().into_alternate_screen().unwrap();
102
103 let (width, height) = terminal_size().unwrap();
104 println!(
105 "{}Screen: {}{}{}",
106 color::Bg(color::Green),
107 self.name,
108 " ".repeat((width - 8 - self.name.len() as u16) as usize),
109 color::Bg(color::Reset)
110 );
111 let width = width as usize;
112 let height = height as usize - 1;
113
114 self.output(0, 0, width, 0, height);
115
116 for i in 0..height {
117 for j in 0..width {
118 if self.buffer[i][j].1 {
119 print!(
120 "{}{}{}",
121 color::Bg(color::Green),
122 self.buffer[i][j].0 as char,
123 color::Bg(color::Reset)
124 );
125 } else {
126 print!("{}", self.buffer[i][j].0 as char);
127 }
128 }
129 }
130 scr.flush().unwrap();
131 }
132 fn output(
133 &mut self,
134 id: usize,
135 start_width: usize,
136 mut end_width: usize,
137 start_height: usize,
138 mut end_height: usize,
139 ) {
140 match self.windows[id].as_ref().unwrap().priority {
141 Some(Priority::Vertical) => {
142 let mit = (start_width + end_width) / 2;
143 let left_id: usize = *self.windows[id]
144 .as_ref()
145 .unwrap()
146 .left_child
147 .as_ref()
148 .unwrap();
149 self.output(left_id, mit, end_width, start_height, end_height);
150 end_width = mit;
151 if let Some(down_id) = self.windows[id].as_ref().unwrap().down_child.as_ref() {
152 let mit = (start_height + end_height) / 2;
153 self.output(*down_id, start_width, end_width, mit, end_height);
154 end_height = mit;
155 }
156 }
157 Some(Priority::Horizontal) => {
158 let mit = (start_height + end_height) / 2;
159 let down_id: usize = *self.windows[id]
160 .as_ref()
161 .unwrap()
162 .down_child
163 .as_ref()
164 .unwrap();
165 self.output(down_id, start_width, end_width, mit, end_height);
166 end_height = mit;
167 if let Some(left_id) = self.windows[id].as_ref().unwrap().left_child.as_ref() {
168 let mit = (start_width + end_width) / 2;
169 self.output(*left_id, mit, end_width, start_height, end_height);
170 end_width = mit;
171 }
172 }
173 None => {}
174 }
175
176 let buffer_size = self.windows[id].as_ref().unwrap().buffer.iter().count();
177
178 let mut it = self.windows[id].as_ref().unwrap().buffer.iter();
179 if buffer_size > end_height - start_height - 1 {
180 it.nth(buffer_size - (end_height - start_height))
181 .unwrap()
182 .as_ref()
183 .unwrap();
184 }
185
186 let empty_line = "-- ".to_string();
187 for i in start_height..end_height - 1 {
188 let line = match it.next() {
189 Some(s) => s.as_ref().unwrap(),
190 None => &empty_line,
191 };
192 let mut letter = line.chars();
193 for j in start_width..end_width {
194 if j == end_width - 1 {
195 self.buffer[i][j] = (b' ', true)
196 } else {
197 self.buffer[i][j] = (
198 match letter.next() {
199 Some(l) => l as u8,
200 None => b' ',
201 },
202 false,
203 )
204 };
205 }
206 }
207
208 let name = format!(
210 "{} ID: {}",
211 self.windows[id].as_ref().unwrap().get_name(),
212 id
213 );
214 let mut c = name.chars();
215 for j in start_width..end_width {
216 self.buffer[end_height - 1][j] = (
217 match c.next() {
218 Some(l) => l as u8,
219 None => b' ',
220 },
221 true,
222 );
223 }
224 }
225 fn validate_id(&self, id: usize) -> Result<(), std::io::ErrorKind> {
227 if id >= MAX_WIN || self.windows[id].is_none(){
229 return Err(std::io::ErrorKind::NotFound);
230 }
231 Ok(())
232 }
233 pub fn append_left_child(&mut self, id: usize) -> Result<usize, std::io::ErrorKind> {
237 self.append_child(id, Priority::Vertical)
238 }
239 pub fn append_down_child(&mut self, id: usize) -> Result<usize, std::io::ErrorKind> {
243 self.append_child(id, Priority::Horizontal)
244 }
245 fn append_child(&mut self, id: usize, priority: Priority) -> Result<usize, std::io::ErrorKind> {
246 if self.count >= MAX_WIN {
248 return Err(std::io::ErrorKind::OutOfMemory);
249 }
250 self.validate_id(id)?;
252
253 let child = match priority {
255 Priority::Vertical => self.windows[id].as_ref().unwrap().left_child,
256 Priority::Horizontal => self.windows[id].as_ref().unwrap().down_child,
257 };
258 if child.is_some() {
259 return Err(std::io::ErrorKind::AlreadyExists);
260 }
261
262 self.windows[self.count] = Some(Window::new(self.count));
263 match priority {
264 Priority::Vertical => self.windows[id].as_mut().unwrap().left_child = Some(self.count),
265 Priority::Horizontal => {
266 self.windows[id].as_mut().unwrap().down_child = Some(self.count)
267 }
268 };
269 if self.windows[id].as_ref().unwrap().priority.is_none() {
270 self.windows[id].as_mut().unwrap().priority = Some(priority);
271 }
272 self.count += 1;
273 Ok(self.count - 1)
274 }
275 pub fn println(&mut self, id: usize, line: &str) -> Result<(), std::io::ErrorKind> {
277 self.validate_id(id)?;
279 self.print(id, line).unwrap();
280 self.flush(id)
281 }
282 pub fn print(&mut self, id: usize, line: &str) -> Result<(), std::io::ErrorKind> {
284 self.validate_id(id)?;
286 self.windows[id].as_mut().unwrap().print(line);
287 Ok(())
288 }
289 pub fn flush(&mut self, id: usize) -> Result<(), std::io::ErrorKind> {
291 self.validate_id(id)?;
293 self.windows[id].as_mut().unwrap().flush();
294 self.load();
295 Ok(())
296 }
297}
298
299impl Default for Screen {
300 fn default() -> Self {
301 Screen::new()
302 }
303}
304enum Cmds {
305 Print,
306 Flush,
307 Println,
308 Break,
309}
310
311pub struct Bridge {
317 bridge: std::sync::mpsc::Sender<(Cmds, usize, String)>,
318 hash: std::collections::HashSet<usize>,
319}
320
321impl Bridge {
322 pub fn new(screen: Screen) -> Self {
325 let (tx, rx) = std::sync::mpsc::channel::<(Cmds, usize, String)>();
326 let mut hash: std::collections::HashSet<usize> = std::collections::HashSet::new();
327 let ids: Vec<usize> = screen
328 .windows
329 .iter()
330 .map(|window| match &window {
331 Some(window) => window.get_id(),
332 None => 0,
333 })
334 .rev()
335 .collect();
336 for id in ids {
337 hash.insert(id);
338 }
339 let screen = Box::new(screen);
340 std::thread::spawn(move || {
341 let mut screen = *screen;
342 for msg in rx.iter() {
343 match msg.0 {
344 Cmds::Print => screen.print(msg.1, &msg.2).unwrap(),
345 Cmds::Flush => screen.flush(msg.1).unwrap(),
346 Cmds::Println => screen.println(msg.1, &msg.2).unwrap(),
347 Cmds::Break => break,
348 };
349 }
350 });
351 Bridge { bridge: tx, hash }
352 }
353 pub fn println(&self, id: usize, msg: &str) -> Result<(), std::io::ErrorKind> {
355 self.validate_id(id)?;
356 self.bridge
357 .send((Cmds::Println, id, msg.to_string()))
358 .unwrap();
359 Ok(())
360 }
361 pub fn print(&self, id: usize, msg: &str) -> Result<(), std::io::ErrorKind> {
363 self.validate_id(id)?;
364 self.bridge
365 .send((Cmds::Print, id, msg.to_string()))
366 .unwrap();
367 Ok(())
368 }
369 pub fn flush(&self, id: usize) -> Result<(), std::io::ErrorKind> {
371 self.validate_id(id)?;
372 self.bridge.send((Cmds::Flush, id, "".to_string())).unwrap();
373 Ok(())
374 }
375 fn validate_id(&self, id: usize) -> Result<(), std::io::ErrorKind> {
376 if self.hash.contains(&id) {
377 return Ok(());
378 }
379 Err(std::io::ErrorKind::NotFound)
380 }
381 pub fn kill(&self) {
383 self.bridge.send((Cmds::Break, 0, "".to_string())).unwrap();
384 }
385}
386
387impl std::clone::Clone for Bridge {
388 fn clone(&self) -> Self {
389 let bridge = self.bridge.clone();
390 let hash = self.hash.clone();
391 Bridge { bridge, hash }
392 }
393 fn clone_from(&mut self, source: &Self) {
394 *self = Bridge::clone(source);
395 }
396}