1use animaterm::{
2 prelude::*,
3 utilities::{message_box, progress_bar},
4};
5use std::collections::HashMap;
6use std::default::Default;
7use std::env;
8use std::path::Path;
9use std::process::exit;
10
11static ROWS_MIN: usize = 4;
12static COLS_MIN: usize = 5;
13
14fn main() {
15 let args = parse_arguments();
16 let cols = args.cols;
17 let rows = args.rows;
18 verify_cols_and_rows(cols, rows);
19 let mut g = Glyph::default();
20 g.set_background(Color::green());
21 g.set_char(char::from_u32(9626).unwrap());
22 g.set_bright(true);
23
24 let mut mgr = Manager::new(true, cols, rows, Some(g), None, None);
25 let (cols, rows) = mgr.screen_size();
26
27 let title = "Navigation help".to_string();
28 let text = "CtrlPgUp,CtrlPgDn, -------------------------------------
29AltPgUp,AltPgDn, ---------------------------------------
30PgUp,PgDn, ---------------------------------------------
31U,D, ---------------------------------------------------
32CtrlU,CtrlD --------------------------------------------
33AltU,AltD ----------------------------------------------
34AltUp | AltK -------------------------------------------
35CtrlUp | CtrlK -----------------------------------------
36Up | K -------------------------------------------------
37AltDown | AltJ -----------------------------------------
38CtrlDown -----------------------------------------------
39Down | J -----------------------------------------------
40AltLeft | AltH -----------------------------------------
41CtrlLeft | Backspace -----------------------------------
42Left | H -----------------------------------------------
43AltRight | AltL ----------------------------------------
44CtrlRight | CtrlL --------------------------------------
45Right | L - all above move graphics around the screen --
46----------- and up/down layers. ------------------------
47Tab - show a message box -------------------------------
48Enter - type some text and hit Enter again -------------
49 "
50 .to_string();
51 let mbox = message_box(Some(title), text, Glyph::default(), 60, 23);
52 let mbid = mgr.add_graphic(mbox, 4, (1, 10)).unwrap();
53 mgr.set_graphic(mbid, 0, true);
54 let (gr, pid) = build_graphic(130, 10);
55 let gr_layer = 1;
56 let gid;
57 let result = mgr.add_graphic(gr, gr_layer, (3, 15));
58 if let Some(id) = result {
59 gid = id;
60 } else {
61 eprintln!("Did not receive first graphic id");
62 exit(2);
63 }
64 mgr.set_graphic(gid, pid, true);
65
66 let pbid;
67 let mut pb_layer = 3;
68 let result = mgr.add_graphic(
69 build_progress_bar(cols - 4),
70 pb_layer,
71 (2, (rows - 2) as isize),
72 );
73 if let Some(id) = result {
74 pbid = id;
75 } else {
76 eprintln!("Did not receive progress bar graphic id");
77 exit(2);
78 }
79 mgr.set_graphic(pbid, 0, true);
80 mgr.start_animation(pbid, 0);
81 let mut mbox_created = false;
82 let mut mbox_id = 100;
83 let mut mbox_layer = 2;
84 if Path::new("index.txg").exists() {
85 if let Some(id) =
86 mgr.add_graphic(Graphic::from_file("index.txg").unwrap(), mbox_layer, (1, 0))
87 {
88 mgr.move_graphic(id, 2, (-1, 0));
89 mbox_id = id;
90 mbox_layer = 4;
91 }
92 } else {
93 eprintln!("\x1b[97;41;5mERR\x1b[m Unable to load index.txg. Run this example from within top examples directory!");
94 eprintln!("\x1b[97;41;5mERR\x1b[m Or copy *.txf and index.txg from there to current dir.");
95 exit(1);
96 }
97
98 loop {
99 if let Some(key) = mgr.read_key() {
100 match key {
101 Key::AltUnicode(uni) => match (uni[2], uni[4]) {
102 (53, 53) => {
103 mgr.move_graphic(1, 4, (0, 0));
105 }
106 (54, 53) => {
107 mgr.move_graphic(1, 1, (0, 0));
109 }
110 (53, 51) => {
111 mgr.move_graphic(2, 5, (0, 0));
113 }
114 (54, 51) => {
115 mgr.move_graphic(2, 2, (0, 0));
117 }
118 _ => {}
119 },
120 Key::PgUp | Key::U => {
121 mgr.move_graphic(0, 3, (0, 0));
122 }
123 Key::PgDn | Key::D => {
124 mgr.move_graphic(0, 0, (0, 0));
125 }
126 Key::CtrlU => {
127 pb_layer = 4;
128 mgr.move_graphic(pbid, pb_layer, (0, 0));
129 }
130 Key::CtrlD => {
131 mgr.move_graphic(pbid, pb_layer, (0, 0));
132 }
133 Key::AltU => {
134 mbox_layer = 5;
135 mgr.move_graphic(mbox_id, mbox_layer, (0, 0));
136 }
137 Key::AltD => {
138 mbox_layer = 2;
139 mgr.move_graphic(mbox_id, mbox_layer, (0, 0));
140 }
141 Key::AltUp | Key::AltK => {
142 mgr.move_graphic(mbox_id, mbox_layer, (0, -1));
143 }
144 Key::CtrlUp | Key::CtrlK => {
145 mgr.move_graphic(pbid, pb_layer, (0, -1));
146 }
147 Key::Up | Key::K => {
148 mgr.stop_animation(gid);
149 mgr.move_graphic(gid, 1, (0, -1));
150 mgr.set_graphic(gid, 1, true);
151 }
152 Key::AltDown | Key::AltJ => {
153 mgr.move_graphic(mbox_id, mbox_layer, (0, 1));
154 }
155 Key::CtrlDown => {
156 mgr.move_graphic(pbid, pb_layer, (0, 1));
157 }
158 Key::Down | Key::J => {
159 mgr.pause_animation_on_frame(pbid, 100);
160 mgr.move_graphic(gid, 1, (0, 1));
161 mgr.set_graphic(gid, pid, true);
162 }
163 Key::AltLeft | Key::AltH => {
164 mgr.move_graphic(mbox_id, mbox_layer, (-1, 0));
165 }
166 Key::CtrlLeft | Key::Backspace => {
167 mgr.move_graphic(pbid, pb_layer, (-1, 0));
168 }
169 Key::Left | Key::H => {
170 mgr.move_graphic(gid, 1, (-1, 0));
171 mgr.start_animation(gid, 0);
172 mgr.start_animation(pbid, 0);
173 }
174 Key::AltRight | Key::AltL => {
175 mgr.move_graphic(mbox_id, mbox_layer, (1, 0));
176 }
177 Key::CtrlRight | Key::CtrlL => {
178 mgr.move_graphic(pbid, pb_layer, (1, 0));
179 }
180 Key::Right | Key::L => {
181 mgr.move_graphic(gid, 1, (1, 0));
182 }
183 Key::Tab => {
184 mbox_layer += 1;
185 if !mbox_created {
186 if let Some(mbid) = mgr.add_graphic(
187 build_mbox(60, 20, "La ku ka ra cza ga wi ga ba ga da da da ja nie".to_string(),
188 "lastBuildDate: Tue, 12 Apr 2022 07:52:44 GMT
189* generator: Oddmuse
190* copyright: This work is licensed to you under version 2 of the GNU General Public License. Alternatively, you may choose to receive this work under
191 any other license that grants the right to use, copy, modify, and distribute the work, as long as that license imposes the restriction that derivative
192 works have to grant the same rights and impose the same restriction. For example, you may choose to receive this work under the GNU Free
193 Documentation License, the CreativeCommons ShareAlike License, the XEmacs manual license, or similar licenses.
194* license: https://creativecommons.org/licenses/sa/1.0/
195* license: https://www.gnu.org/copyleft/fdl.html
196* license: https://www.gnu.org/copyleft/gpl.html".to_string() ),
197 mbox_layer,
198 (0, 0),
199 ){
200 mgr.set_graphic(mbid, 0, true);
201 mbox_created = true;
202 mbox_id = mbid;
203 }
204 }
205 }
206 Key::CtrlA => {
207 mgr.start_animation(gid, 0);
208 }
209 Key::CtrlB => {
210 mgr.stop_animation(gid);
211 }
212 Key::Insert => {
213 mgr.set_graphic(gid, 2, false);
214 }
215 Key::Delete => {}
216 Key::Home => {
217 mgr.set_glyph(gid, Glyph::default(), 1, 1);
218 mgr.move_graphic(gid, 1, (0, 0));
219 mgr.empty_frame(gid);
220 }
221 Key::Escape | Key::Q | Key::CtrlQ => {
222 break;
223 }
224 Key::Enter => {
225 if !mbox_created {
226 mbox_layer += 1;
227 if let Some(tid) = mgr.add_graphic(
228 build_mbox(
229 40,
230 1,
231 "Please enter title and hit Enter".to_string(),
232 String::new(),
233 ),
234 mbox_layer,
235 (cols as isize / 2 - 20, rows as isize / 2),
236 ) {
237 mgr.set_graphic(tid, 0, true);
238 let line = mgr.read_line();
239 if let Some(mbid) = mgr.add_graphic(
240 build_mbox(
241 60,
242 20,
243 line,
244 "Hit Enter to type content in.".to_string(),
245 ),
246 mbox_layer,
247 (0, 0),
248 ) {
249 mgr.delete_graphic(tid);
250 mbox_id = mbid;
251 mgr.set_graphic(mbid, 0, true);
252 mbox_created = true;
253 }
254 }
255 } else {
256 let mut x = 1;
257 let mut y = 1;
258 mbox_created = false;
259 let mut rev = Glyph::default();
260 rev.set_reverse(true);
261 for i in 1..31 {
262 mgr.set_glyph(mbox_id, rev, i, 1);
263 }
264 loop {
265 if let Some(c) = mgr.read_char() {
266 if c == '\t' {
267 break;
268 }
269 if c as u8 == 8 || c as u8 == 127 {
270 x -= 1;
271 if x == 0 {
272 if y > 1 {
273 y -= 1;
274 x = 58;
275 } else {
276 x = 1;
277 }
278 }
279 mgr.set_glyph(mbox_id, Glyph::default(), x, y);
280 continue;
281 }
282 if c == '\n' {
283 break;
284 }
285
286 mgr.set_glyph(mbox_id, Glyph::default_with_char(c), x, y);
287 x += 1;
288 if x > 58 {
289 x = 1;
290 y += 1;
291 }
292 }
293 }
294 }
295 }
296 _ => {
297 println!("You pressed: {:?}", key);
298 }
299 }
300 }
301 }
302 mgr.terminate();
303}
304
305struct Arguments {
306 rows: Option<usize>,
307 cols: Option<usize>,
308}
309
310impl Default for Arguments {
311 fn default() -> Self {
312 Arguments {
313 rows: None,
314 cols: None,
315 }
316 }
317}
318
319enum ArgType {
320 Rows,
321 Cols,
322 }
324
325enum WhatToParse {
326 Name,
327 Number,
328 }
330
331fn parse_arguments() -> Arguments {
332 let mut arguments = Arguments::default();
333 let mut what_to_parse = WhatToParse::Name;
334 let mut args = env::args();
335 let mut program_name = args.next().unwrap();
336 if let Some(value) = program_name.split("/").last() {
337 program_name = value.to_string();
338 };
339 let mut name = None;
340 let mut number; for arg in args {
343 if arg == "--help" {
344 println!("Usage:");
345 println!(
346 "{} --argument value",
347 program_name.split("/").last().unwrap()
348 );
349 println!("\n Optional arguments:");
350 println!(" --help - print this message");
351 println!(
352 " --rows <number> - how many rows should the screen consist of (at least {})",
353 ROWS_MIN
354 );
355 println!(
356 " --cols <number> - how many columns should be in each line (at least {})",
357 COLS_MIN
358 );
359 exit(0)
360 }
361 match what_to_parse {
362 WhatToParse::Name => {
363 if arg.starts_with("--") {
364 name = match &arg[2..] {
365 "rows" => Some(ArgType::Rows),
366 "cols" => Some(ArgType::Cols),
367 &_ => None,
368 };
369 what_to_parse = WhatToParse::Number;
371 } else {
372 eprintln!(
373 "\x1b[97;41;5mERR\x1b[m Expected argument name (e.g. --argument), got: {}",
374 arg
375 );
376 exit(1);
377 }
378 }
379 WhatToParse::Number => {
380 let parsed_number = usize::from_str_radix(arg.trim(), 10);
381 match parsed_number {
382 Ok(a_number) => {
383 number = Some(a_number);
384 match &name {
385 Some(ArgType::Cols) => arguments.cols = number,
386 Some(ArgType::Rows) => arguments.rows = number,
387 None => {}
388 }
389 }
390 Err(_e) => {
391 eprintln!(
392 "\x1b[97;41;5mERR\x1b[m Expected integer value (e.g. 42), got: {}",
393 arg
394 );
395 exit(1);
396 }
397 }
398 what_to_parse = WhatToParse::Name;
399 println!("Parsing for number: {}", number.unwrap());
400 } }
404 }
405 arguments
406}
407
408fn build_graphic(cols: usize, rows: usize) -> (Graphic, usize) {
409 let start_frame = 0;
410 let mut library = HashMap::with_capacity(2);
411 library.insert(
412 start_frame,
413 vec![
414 Glyph::new(
415 '\u{2580}',
416 animaterm::Color::new_8bit(0, 5, 0),
417 animaterm::Color::new_8bit(0, 0, 5),
418 false,
419 true,
420 false,
421 false,
422 false,
423 false,
424 false,
425 false,
426 false,
427 false,
428 );
429 rows * cols
430 ],
431 );
432 let mut animations = HashMap::new();
433 animations.insert(
434 0,
435 Animation::new(
436 false,
437 true,
438 vec![(1, Timestamp::new(0, 500)), (0, Timestamp::new(0, 500))],
439 Timestamp::now(),
440 ),
441 );
442
443 let mut gr = Graphic::new(cols, rows, start_frame, library, Some(animations));
444 let pid = gr
445 .add_to_library(vec![
446 Glyph::new(
447 '\u{2580}',
448 animaterm::Color::new_truecolor(0, 255, 255),
449 animaterm::Color::new_truecolor(0, 0, 255),
450 false,
451 true,
452 false,
453 false,
454 false,
455 false,
456 false,
457 false,
458 false,
459 false,
460 );
461 rows * cols
462 ])
463 .unwrap();
464 (gr, pid)
465}
466
467fn build_mbox(cols: usize, rows: usize, title: String, content: String) -> Graphic {
468 message_box(
469 Some(title),
470 content,
471 Glyph::new(
472 ' ',
473 animaterm::Color::new_gray(0),
474 animaterm::Color::new_gray(22),
475 false,
476 false,
477 false,
478 false,
479 false,
480 false,
481 false,
482 false,
483 false,
484 false,
485 ),
486 cols,
487 rows,
488 )
489}
490
491fn build_progress_bar(length: usize) -> Graphic {
492 let glf = Glyph::new(
493 '\u{2588}',
494 animaterm::Color::new(ColorName::Red),
495 animaterm::Color::new(ColorName::White),
496 false,
497 true,
498 false,
499 false,
500 false,
501 false,
502 false,
503 false,
504 false,
505 false,
506 );
507 progress_bar(
508 length,
509 Glyph::transparent(),
510 glf,
511 Some(vec![
512 Glyph::new(
513 '\u{258F}',
514 animaterm::Color::red(),
515 animaterm::Color::cyan(),
516 false,
517 true,
518 false,
519 false,
520 false,
521 false,
522 false,
523 false,
524 false,
525 false,
526 ),
527 Glyph::new(
528 '\u{258E}',
529 animaterm::Color::red(),
530 animaterm::Color::cyan(),
531 false,
532 true,
533 false,
534 false,
535 false,
536 false,
537 false,
538 false,
539 false,
540 false,
541 ),
542 Glyph::new(
543 '\u{258D}',
544 animaterm::Color::red(),
545 animaterm::Color::cyan(),
546 false,
547 true,
548 false,
549 false,
550 false,
551 false,
552 false,
553 false,
554 false,
555 false,
556 ),
557 Glyph::new(
558 '\u{258C}',
559 animaterm::Color::red(),
560 animaterm::Color::cyan(),
561 false,
562 true,
563 false,
564 false,
565 false,
566 false,
567 false,
568 false,
569 false,
570 false,
571 ),
572 Glyph::new(
573 '\u{258B}',
574 animaterm::Color::red(),
575 animaterm::Color::cyan(),
576 false,
577 true,
578 false,
579 false,
580 false,
581 false,
582 false,
583 false,
584 false,
585 false,
586 ),
587 Glyph::new(
588 '\u{258A}',
589 animaterm::Color::red(),
590 animaterm::Color::cyan(),
591 false,
592 true,
593 false,
594 false,
595 false,
596 false,
597 false,
598 false,
599 false,
600 false,
601 ),
602 ]),
618 )
619}
620
621fn verify_cols_and_rows(cols: Option<usize>, rows: Option<usize>) {
622 if let Some(a_rows) = rows {
623 if a_rows < ROWS_MIN {
624 eprintln!(
625 "\x1b[97;41;5mERR\x1b[m Min rows: {}, you provided: {}",
626 ROWS_MIN, a_rows
627 );
628 exit(1)
629 }
630 }
631 if let Some(a_cols) = cols {
632 if a_cols < COLS_MIN {
633 eprintln!(
634 "\x1b[97;41;5mERR\x1b[m Min cols: {}, you provided: {}",
635 COLS_MIN, a_cols
636 );
637 exit(1)
638 }
639 }
640}