example_5/
example_5.rs

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                        //CtrlPgUp
104                        mgr.move_graphic(1, 4, (0, 0));
105                    }
106                    (54, 53) => {
107                        //CtrlPgDn
108                        mgr.move_graphic(1, 1, (0, 0));
109                    }
110                    (53, 51) => {
111                        //AltPgUp
112                        mgr.move_graphic(2, 5, (0, 0));
113                    }
114                    (54, 51) => {
115                        //AltPgDn
116                        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    // Unknown,
323}
324
325enum WhatToParse {
326    Name,
327    Number,
328    // Text,
329}
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; // = None;
341                    // let text: Option<String> = None;
342    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                    // println!("Parsing for name: {}", name.unwrap());
370                    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            } // WhatToParse::Text => {
401              //     println!("Parsing for text: {}", arg);
402              // }
403        }
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            // Glyph::new(
603            //     '\u{2589}',
604            //     animaterm::Color::new_truecolor(128, 0, 0),
605            //     animaterm::Color::cyan(),
606            //     false,
607            //     true,
608            //     false,
609            //     false,
610            //     false,
611            //     false,
612            //     false,
613            //     false,
614            //     false,
615            //     false,
616            // ),
617        ]),
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}