1use piston_window::{*, types::{Color, FontSize}};
2use std::{thread, time::{Duration, Instant}};
3
4use crate::{draw::*, text::*, TYPE_TIME};
5
6pub struct Terminal {
9 title: String,
10 active: bool,
11 pub window: PistonWindow,
13 pub bg_color: Color,
15 pub fg_color: Color,
17 pub scanlines: bool,
19 glyphs: Glyphs,
20 font: String,
21 art_font: String,
22 pub font_size: FontSize,
24 pub art_font_size: FontSize,
26 art_mode: bool,
27 message: Vec<String>,
28 input: String,
29}
30
31impl Terminal {
32 pub fn new(title: &str, size: (u32, u32), bg: Color, fg: Color, font: &str, font_size: u32) -> Terminal {
40 let mut new_window: PistonWindow = WindowSettings::new(title, size).exit_on_esc(true).build().unwrap();
41 let loaded_glyphs = load_font(&mut new_window, font);
42
43 Terminal {
44 title: String::from(title),
45 active: true,
46 window: new_window,
47 bg_color: bg,
48 fg_color: fg,
49 scanlines: true,
50 glyphs: loaded_glyphs,
51 font: String::from(font),
52 art_font: String::from("LeagueMono-Regular.ttf"),
53 font_size,
54 art_font_size: 10,
55 art_mode: false,
56 message: Vec::new(),
57 input: String::default(),
58 }
59 }
60
61 pub fn ask(&mut self, message: &str) -> Option<String> {
71 if self.active {
72 if self.art_mode {
73 self.glyphs = load_font(&mut self.window, &self.font);
74 self.art_mode = false;
75 }
76
77 self.new_message(message);
78 self.wait_for_input();
79 Some(self.input.clone())
80 } else {
81 None
82 }
83 }
84
85 pub fn display_art(&mut self, art: &str, time: Duration) {
95 if self.active {
96 if !self.art_mode {
97 self.glyphs = load_font(&mut self.window, &self.art_font);
98 self.art_mode = true;
99 }
100
101 self.message = art.split('\n').map(String::from).collect();
102 self.input = String::default();
103 self.show_art(time);
104 }
105 }
106
107 pub fn show(&mut self, message: &str, time: Duration) {
117 if self.active {
118 if self.art_mode {
119 self.glyphs = load_font(&mut self.window, &self.font);
120 self.art_mode = false;
121 }
122
123 self.new_message(message);
124 self.wait_for_timer(time);
125 }
126 }
127
128 pub fn tell(&mut self, message: &str) {
137 if self.active {
138 if self.art_mode {
139 self.glyphs = load_font(&mut self.window, &self.font);
140 self.art_mode = false;
141 }
142
143 self.new_message(message);
144 self.input = String::from("Press Enter to Continue");
145 self.wait_for_continue();
146 }
147 }
148
149 pub fn resize(&mut self, new_size: Size) {
158 if self.active {
159 let new_window: PistonWindow = WindowSettings::new(self.title.clone(), new_size).exit_on_esc(true).build().unwrap();
160 self.window = new_window;
161 }
162 }
163
164 pub fn set_font(&mut self, font: &str, size: FontSize) {
173 if self.active {
174 if !self.art_mode { self.glyphs = load_font(&mut self.window, font); }
175 self.font = String::from(font);
176 self.font_size = size;
177 }
178 }
179
180 pub fn set_art_font(&mut self, font: &str, size: FontSize) {
192 if self.active {
193 if self.art_mode { self.glyphs = load_font(&mut self.window, font); }
194 self.art_font = String::from(font);
195 self.art_font_size = size;
196 }
197 }
198
199 pub fn set_colors(&mut self, bgc: Color, fgc: Color) {
208 self.bg_color = bgc;
209 self.fg_color = fgc;
210 }
211
212 fn show_art(&mut self, timer: Duration) {
214 let bgc: Color = self.bg_color;
215 let fgc: Color = self.fg_color;
216
217 let art: &Vec<String> = &self.message;
218 let glyphs: &mut Glyphs = &mut self.glyphs;
219 let font_size: FontSize = self.art_font_size;
220 let use_filter: bool = self.scanlines;
221
222 let start: Instant = Instant::now();
223 let mut active: bool = self.active;
224 while let Some(e) = self.window.next() {
225 e.close(|_| { active = false; });
226
227 let win_size: Size = self.window.window.size();
228
229 let now: Instant = Instant::now();
230 if now.duration_since(start) > timer { break; }
231
232 self.window.draw_2d(&e, |c, g, device| {
233 clear(bgc, g);
234
235 draw_background(win_size, bgc, fgc, use_filter, c, g);
236 draw_art(win_size, art, glyphs, font_size, fgc, c, g);
237 draw_foreground(win_size, bgc, use_filter, c, g);
238
239 glyphs.factory.encoder.flush(device);
240 });
241 }
242 self.active = active;
243 }
244
245 fn type_message(&mut self) {
247 let bgc: Color = self.bg_color;
248 let fgc: Color = self.fg_color;
249 let current_input: &str = &(self.input[..]);
250 let glyphs = &mut self.glyphs;
251 let font_size: FontSize = self.font_size;
252
253 let mut typed_message: Vec<String> = Vec::new();
254 let use_filter: bool = self.scanlines;
255
256 let mut active: bool = self.active;
257 for (i, line) in self.message.iter().enumerate() {
258 typed_message.push(String::default());
259
260 let line_len: usize = line.len();
261 for j in 1..line_len {
262 typed_message[i] = String::from(&line[..=j]);
263 typed_message[i].push_str("[]");
264 if let Some(e) = self.window.next() {
265 e.close(|_| { active = false; });
266
267 let win_size: Size = self.window.window.size();
268
269 self.window.draw_2d(&e, |c, g, device| {
270 clear(bgc, g);
271
272 draw_background(win_size, bgc, fgc, use_filter, c, g);
273 draw_message(&typed_message, glyphs, font_size, fgc, c, g);
274 draw_input(win_size, current_input, glyphs, font_size, fgc, c, g);
275 draw_foreground(win_size, bgc, use_filter, c, g);
276
277 glyphs.factory.encoder.flush(device);
278 });
279 thread::sleep(TYPE_TIME);
280 }
281 typed_message[i].pop();
282 typed_message[i].pop();
283 }
284 }
285 self.active = active;
286 }
287
288 fn wait_for_continue(&mut self) {
290 let mut ready: bool = false;
291
292 let bgc: Color = self.bg_color;
293 let fgc: Color = self.fg_color;
294
295 let message: &Vec<String> = &self.message;
296 let current_input: &str = &(self.input);
297 let glyphs: &mut Glyphs = &mut self.glyphs;
298 let font_size: FontSize = self.font_size;
299 let use_filter: bool = self.scanlines;
300
301 let mut start: Instant = Instant::now();
302 let mut active: bool = self.active;
303 while let Some(e) = self.window.next() {
304 e.close(|_| { active = false; });
305
306 let win_size: Size = self.window.window.size();
307
308 e.button(|button_args| {
309 if let Button::Keyboard(key) = button_args.button {
310 if button_args.state == ButtonState::Press && key == Key::Return { ready = true; }
311 }
312 });
313
314 if ready { break; }
315
316 let now: Instant = Instant::now();
317 self.window.draw_2d(&e, |c, g, device| {
318 clear(bgc, g);
319
320 draw_background(win_size, bgc, fgc, use_filter, c, g);
321 draw_message(message, glyphs, font_size, fgc, c, g);
322 draw_input_marker(win_size, glyphs, font_size, fgc, c, g);
323 if check_flash(now, &mut start) { draw_input(win_size, current_input, glyphs, font_size, fgc, c, g); }
324 draw_foreground(win_size, bgc, use_filter, c, g);
325
326 glyphs.factory.encoder.flush(device);
327 });
328 }
329 self.active = active;
330 }
331
332 fn wait_for_input(&mut self) {
334 let mut input_string: String = String::default();
335 let mut input_accepted: bool = false;
336
337 let bgc: Color = self.bg_color;
338 let fgc: Color = self.fg_color;
339
340 let message: &Vec<String> = &self.message;
341 let glyphs: &mut Glyphs = &mut self.glyphs;
342 let font_size: FontSize = self.font_size;
343 let use_filter: bool = self.scanlines;
344
345 let mut start: Instant = Instant::now();
346 let mut active: bool = self.active;
347 while let Some(e) = self.window.next() {
348 e.close(|_| { active = false; });
349
350 let win_size: Size = self.window.window.size();
351
352 e.text(|text| input_string.push_str(text));
353 e.button(|button_args| {
354 if let Button::Keyboard(key) = button_args.button {
355 if button_args.state == ButtonState::Press {
356 if key == Key::Backspace { input_string.pop(); }
357 if key == Key::Return && input_string != "" { input_accepted = true; }
358 }
359 }
360 });
361
362 if input_accepted {
363 self.input = input_string.clone();
364 input_string = String::default();
365 }
366
367 let now: Instant = Instant::now();
368 self.window.draw_2d(&e, |c, g, device| {
369 clear(bgc, g);
370
371 draw_background(win_size, bgc, fgc, use_filter, c, g);
372 draw_message(message, glyphs, font_size, fgc, c, g);
373 draw_input_marker(win_size, glyphs, font_size, fgc, c, g);
374
375 if check_flash(now, &mut start) {
376 input_string.push_str("[]");
377 draw_input(win_size, &input_string[..], glyphs, font_size, fgc, c, g);
378 input_string.pop();
379 input_string.pop();
380 } else {
381 draw_input(win_size, &input_string[..], glyphs, font_size, fgc, c, g);
382 }
383
384 draw_foreground(win_size, bgc, use_filter, c, g);
385
386 glyphs.factory.encoder.flush(device);
387 });
388
389 if input_accepted { break; }
390 }
391 self.active = active;
392 }
393
394 fn wait_for_timer(&mut self, timer: Duration) {
396 let bgc: Color = self.bg_color;
397 let fgc: Color = self.fg_color;
398
399 let message: &Vec<String> = &self.message;
400 let glyphs: &mut Glyphs = &mut self.glyphs;
401 let font_size: FontSize = self.font_size;
402 let use_filter: bool = self.scanlines;
403
404 let start: Instant = Instant::now();
405 let mut active: bool = self.active;
406 while let Some(e) = self.window.next() {
407 e.close(|_| { active = false; });
408
409 let win_size: Size = self.window.window.size();
410
411 let now: Instant = Instant::now();
412 if now.duration_since(start) > timer { break; }
413
414 self.window.draw_2d(&e, |c, g, device| {
415 clear(bgc, g);
416
417 draw_background(win_size, bgc, fgc, use_filter, c, g);
418 draw_message(message, glyphs, font_size, fgc, c, g);
419 draw_foreground(win_size, bgc, use_filter, c, g);
420
421 glyphs.factory.encoder.flush(device);
422 });
423 }
424 self.active = active;
425 }
426
427 fn new_message(&mut self, message: &str) {
429 self.message = message.split('\n').map(String::from).collect();
430 self.process_message();
431 self.input = String::default();
432 self.type_message();
433 }
434
435 fn process_message(&mut self) {
437 let max_chars: usize = self.get_max_characters();
438
439 let mut new_message_vec: Vec<String> = Vec::new();
440
441 for old_message in self.message.iter() {
442 let mut new_message: String = String::new();
443
444 for word in old_message.split_whitespace() {
445 let word_len: usize = word.len();
446 let message_len: usize = new_message.len();
447
448 if word_len > max_chars {
449 if message_len > 0 {
450 let word_vec = split_word(word, max_chars - (message_len + 1), max_chars);
451 let mut word_iter = word_vec.iter();
452 new_message_vec.push(format!("{} {}", new_message, word_iter.next().unwrap()));
453 for continued_word in word_iter {
454 new_message_vec.push(continued_word.to_string());
455 }
456 new_message = new_message_vec.pop().unwrap();
457 } else {
458 new_message_vec.append(&mut split_word(word, max_chars, max_chars));
459 }
460 } else if message_len + word_len > max_chars {
461 new_message_vec.push(new_message);
462 new_message = String::from(word);
463 } else if message_len > 0 {
464 new_message = format!("{} {}", new_message, word);
465 } else {
466 new_message = String::from(word);
467 }
468 }
469 if !new_message.is_empty() { new_message_vec.push(new_message); }
470 }
471 self.message = new_message_vec;
472 }
473
474 fn get_max_characters(&self) -> usize {
476 ((self.window.window.size().width / self.font_size as f64) * 2.15) as usize
477 }
478}