Skip to main content

test2/
test2.rs

1//! Page update test.  Uses Page-based update of the terminal
2//! (`Output::update_to`)
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, Page, 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    page: Page,
41    spacing: i32,
42    spacing_on: bool,
43}
44
45impl App {
46    fn init(cx: CX![]) -> Option<Self> {
47        let _terminal = actor!(
48            cx,
49            Terminal::init(
50                SimpleSizer::new(),
51                fwd_to!([cx], resize() as (Option<TermShare>)),
52                fwd_to!([cx], input() as (Key))
53            ),
54            ret_some_to!([cx], |_, cx, cause: StopCause| {
55                println!("Terminal actor failed: {cause}");
56                stop!(cx);
57            })
58        );
59        Some(Self {
60            _terminal,
61            tshare: None,
62            page: Page::empty(),
63            spacing: 0,
64            spacing_on: false,
65        })
66    }
67
68    fn resize(&mut self, cx: CX![], tshare: Option<TermShare>) {
69        self.tshare = tshare;
70
71        if let Some(ref tshare) = self.tshare {
72            let o = tshare.output(cx);
73            o.attr_99().cursor_show().scroll_up().save_cleanup();
74            o.cursor_hide();
75            self.page = o.new_page();
76        }
77
78        self.redraw(cx, true);
79    }
80
81    fn input(&mut self, cx: CX![], key: Key) {
82        match key {
83            Key::Ctrl('L') => self.redraw(cx, true),
84            Key::Ctrl('C') => stop!(cx),
85            _ => {
86                if self.spacing_on {
87                    self.spacing_on = false;
88                } else {
89                    self.spacing_on = true;
90                    self.spacing = ((self.spacing + 1) % 20).max(3);
91                }
92                self.redraw(cx, false);
93            }
94        }
95    }
96
97    fn redraw(&mut self, cx: CX![], full: bool) {
98        let pg = &mut self.page;
99        let sx = pg.sx();
100        let sy = pg.sy();
101
102        if sy < 24 || sx < 80 {
103            let mut r = pg.full();
104            r.clear_all_99();
105            r.at(sy >> 1, (sx - 30) >> 1).hfb(162);
106            write!(r, " Terminal too small: {sy} x {sx} ").unwrap();
107            return;
108        }
109
110        const TEXT: &str = "This is a test.  ";
111        const TEXTLEN: usize = TEXT.len();
112        let mid = sx >> 1;
113        for y in 0..sy {
114            let mut r = pg.region(y, 0, 1, sx + TEXTLEN as i32 * 2);
115            r.at(0, y % TEXTLEN as i32 - TEXTLEN as i32).hfb(99);
116            while r.get_x() < sx {
117                r.text(TEXT);
118            }
119            if self.spacing_on {
120                let mut x = (sx + sy) / 2 - y;
121                while x > 0 {
122                    x -= self.spacing
123                }
124                r.at(0, x);
125                while r.get_x() < sx {
126                    r.text("/");
127                    r.skip(self.spacing - 1);
128                }
129            }
130            let shift = y * 6 / sy;
131            for x in 0..sx {
132                r.set_hfb(0, x, (((x - mid) >> shift) & 3) as u16 + 70);
133            }
134        }
135        pg.full()
136            .at(sy - 2, (sx - 40) >> 1)
137            .hfb(6)
138            .text("  PRESS ANY KEY TO CONTINUE, Ctrl-C TO END  ");
139
140        self.update(cx, full);
141    }
142
143    fn update(&mut self, cx: CX![], full: bool) {
144        if let Some(ref tshare) = self.tshare {
145            let o = tshare.output(cx);
146            o.update_to(&mut self.page, full);
147        }
148    }
149}