Skip to main content

test1/
test1.rs

1//! Colour-combination and keypress detection test.  Uses direct
2//! access via `Output`.
3use stakker::{ActorOwn, CX, Stakker, StopCause, actor, fwd_to, ret_shutdown, ret_some_to, stop};
4use stakker_mio::MioPoll;
5use stakker_mio::mio::{Events, Poll};
6use stakker_tui::{Key, Output, TermShare, Terminal, sizer::SimpleSizer};
7use std::io::Write;
8use std::time::{Duration, Instant};
9
10// Let main loop dump setup I/O errors to console.  You could catch
11// them instead if you want.
12fn main() -> std::io::Result<()> {
13    let mut stakker = Stakker::new(Instant::now());
14    let s = &mut stakker;
15    let miopoll = MioPoll::new(s, Poll::new()?, Events::with_capacity(1024), 0)?;
16
17    let _app = actor!(s, App::init(), ret_shutdown!(s));
18
19    const MAXDELAY: Duration = Duration::from_secs(60);
20    let mut idle_pending = s.run(Instant::now(), false);
21    let mut io_pending = false;
22    let mut activity;
23    while s.not_shutdown() {
24        let maxdur = s.next_wait_max(Instant::now(), MAXDELAY, idle_pending || io_pending);
25        (activity, io_pending) = miopoll.poll(maxdur)?;
26        idle_pending = s.run(Instant::now(), !activity);
27    }
28    if let Some(reason) = s.shutdown_reason() {
29        if reason.has_error() {
30            println!("{reason}");
31        }
32    }
33
34    Ok(())
35}
36
37struct App {
38    _terminal: ActorOwn<Terminal>,
39    tshare: Option<TermShare>,
40}
41
42impl App {
43    fn init(cx: CX![]) -> Option<Self> {
44        let _terminal = actor!(
45            cx,
46            Terminal::init(
47                SimpleSizer::new(),
48                fwd_to!([cx], resize() as (Option<TermShare>)),
49                fwd_to!([cx], input() as (Key))
50            ),
51            ret_some_to!([cx], |_, cx, cause: StopCause| {
52                println!("Terminal actor failed: {cause}");
53                stop!(cx);
54            })
55        );
56        Some(Self {
57            _terminal,
58            tshare: None,
59        })
60    }
61
62    fn resize(&mut self, cx: CX![], tshare: Option<TermShare>) {
63        self.tshare = tshare;
64        if self.tshare.is_some() {
65            self.redraw(cx);
66        }
67    }
68
69    fn redraw(&mut self, cx: CX![]) {
70        if let Some(ref tshare) = self.tshare {
71            let o = tshare.output(cx);
72            o.attr_99().cursor_show().scroll_up().save_cleanup();
73            o.cursor_hide();
74            Self::draw(o);
75        }
76    }
77
78    fn input(&mut self, cx: CX![], key: Key) {
79        match key {
80            Key::Ctrl('L') => self.redraw(cx),
81            Key::Ctrl('C') => stop!(cx),
82            _ => {
83                use std::str::FromStr;
84                let s = format!("{key}");
85                let k = Key::from_str(&s);
86                assert!(k.is_ok(), "Round-trip failed for {s}");
87                let k = k.unwrap();
88                assert_eq!(k, key, "Mismatch for {key} -> {s} -> {k}");
89                let hfb = if s.starts_with("M-") {
90                    172
91                } else if s.starts_with("C-") {
92                    141
93                } else if matches!(key, Key::Pr(_)) {
94                    151
95                } else {
96                    162
97                };
98                if let Some(ref tshare) = self.tshare {
99                    let o = tshare.output(cx);
100                    o.hfb(hfb).text(&s);
101                    o.hfb(71).text(" ");
102                    o.flush();
103                }
104            }
105        }
106    }
107
108    fn draw(o: &mut Output) {
109        o.clear_all_99();
110        let sx = o.sx();
111        let sy = o.sy();
112        if sy < 24 || sx < 80 {
113            o.hfb(162);
114            o.at(o.sy() >> 1, (o.sx() - 30) >> 1);
115            write!(o, " Terminal too small: {} x {} ", o.sy(), o.sx()).unwrap();
116            o.hfb(99);
117            o.flush();
118            return;
119        }
120
121        const TEXT: [char; 17] = [
122            'T', 'h', 'i', 's', ' ', 'i', 's', ' ', 'a', ' ', 't', 'e', 's', 't', '.', ' ', ' ',
123        ];
124        let mut last_hfb = 99;
125        for y in 0..sy {
126            o.at(y, 0);
127            for x in 0..sx {
128                let hfb = ((x * 8) / sx + (y & 7) * 10 + ((y >> 3) & 1) * 100) as u16;
129                if hfb != last_hfb {
130                    o.hfb(hfb);
131                    last_hfb = hfb;
132                }
133                o.char(TEXT[(1000 + x - y) as usize % TEXT.len()]);
134            }
135        }
136        o.at(sy - 2, (sx - 60) / 2)
137            .hfb(162)
138            .text("[ Type to show decoding, Ctrl-C to exit, Ctrl-L to redraw ]")
139            .hfb(99);
140        o.at(0, 0);
141        o.flush();
142    }
143}