cursive_core/
cursive_run.rs

1use crate::{backend, buffer, event, Cursive, Vec2};
2use parking_lot::RwLock;
3use std::borrow::{Borrow, BorrowMut};
4use std::time::Duration;
5
6// How long we wait between two empty input polls
7const INPUT_POLL_DELAY_MS: u64 = 30;
8
9/// Event loop runner for a cursive instance.
10///
11/// You can get one from `Cursive::runner`, then either call `.run()`, or
12/// manually `.step()`.
13///
14/// The `C` type is usually either `Cursive` or `&mut Cursive`.
15pub struct CursiveRunner<C> {
16    siv: C,
17
18    backend: Box<dyn backend::Backend>,
19    buffer: RwLock<buffer::PrintBuffer>,
20
21    boring_frame_count: u32,
22    // Last layer sizes of the stack view.
23    // If it changed, clear the screen.
24    last_sizes: Vec<Vec2>,
25}
26
27impl<C> std::ops::Deref for CursiveRunner<C>
28where
29    C: Borrow<Cursive>,
30{
31    type Target = Cursive;
32
33    fn deref(&self) -> &Cursive {
34        self.siv.borrow()
35    }
36}
37
38impl<C> std::ops::DerefMut for CursiveRunner<C>
39where
40    C: BorrowMut<Cursive>,
41{
42    fn deref_mut(&mut self) -> &mut Cursive {
43        self.siv.borrow_mut()
44    }
45}
46
47impl<C> CursiveRunner<C> {
48    /// Creates a new cursive runner wrapper.
49    pub fn new(siv: C, backend: Box<dyn backend::Backend>) -> Self {
50        CursiveRunner {
51            siv,
52            backend,
53            buffer: RwLock::new(buffer::PrintBuffer::new()),
54            boring_frame_count: 0,
55            last_sizes: Vec::new(),
56        }
57    }
58
59    /// Returns the size of the screen, in characters.
60    fn screen_size(&self) -> Vec2 {
61        self.backend.screen_size()
62    }
63
64    /// Clean out the terminal and get back the wrapped object.
65    pub fn into_inner(self) -> C {
66        self.siv
67    }
68}
69
70impl<C> CursiveRunner<C>
71where
72    C: BorrowMut<Cursive>,
73{
74    fn layout(&mut self) {
75        let size = self.screen_size();
76        self.siv.borrow_mut().layout(size);
77    }
78
79    // Process any backend-requiring calls accumulated by the Cursive root.
80    fn process_pending_backend_calls(&mut self) {
81        let calls = std::mem::take(&mut self.backend_calls);
82        for call in calls {
83            (call)(&mut *self.backend);
84        }
85    }
86
87    fn draw(&mut self) {
88        let sizes = self.screen().layer_sizes();
89        if self.last_sizes != sizes {
90            // TODO: Maybe we only need to clear if the _max_ size differs?
91            // Or if the positions change?
92            self.clear();
93            self.last_sizes = sizes;
94        }
95
96        self.buffer.write().resize(self.screen_size());
97        self.siv.borrow_mut().draw(&self.buffer);
98        self.buffer.write().flush(&*self.backend);
99    }
100
101    /// Performs the first half of `Self::step()`.
102    ///
103    /// This is an advanced method for fine-tuned manual stepping;
104    /// you probably want [`run`][1] or [`step`][2].
105    ///
106    /// This processes any pending event or callback. After calling this,
107    /// you will want to call [`post_events`][3] with the result from this
108    /// function.
109    ///
110    /// Returns `true` if an event or callback was received,
111    /// and `false` otherwise.
112    ///
113    /// [1]: CursiveRunner::run()
114    /// [2]: CursiveRunner::step()
115    /// [3]: CursiveRunner::post_events()
116    pub fn process_events(&mut self) -> bool {
117        // Things are boring if nothing significant happened.
118        let mut boring = true;
119
120        // First, handle all available input
121        while let Some(event) = self.backend.poll_event() {
122            boring = false;
123            self.on_event(event);
124            self.process_pending_backend_calls();
125
126            if !self.is_running() {
127                return true;
128            }
129        }
130
131        // Then, handle any available callback
132        while self.process_callback() {
133            boring = false;
134
135            if !self.is_running() {
136                return true;
137            }
138        }
139
140        !boring
141    }
142
143    /// Performs the second half of `Self::step()`.
144    ///
145    /// This is an advanced method for fine-tuned manual stepping;
146    /// you probably want [`run`][1] or [`step`][2].
147    ///
148    /// You should call this after [`process_events`][3].
149    ///
150    /// [1]: CursiveRunner::run()
151    /// [2]: CursiveRunner::step()
152    /// [3]: CursiveRunner::process_events()
153    pub fn post_events(&mut self, received_something: bool) {
154        let boring = !received_something;
155        // How many times should we try if it's still boring?
156        // Total duration will be INPUT_POLL_DELAY_MS * repeats
157        // So effectively fps = 1000 / INPUT_POLL_DELAY_MS / repeats
158        if !boring
159            || self
160                .fps()
161                .map(|fps| 1000 / INPUT_POLL_DELAY_MS as u32 / fps.get())
162                .map(|repeats| self.boring_frame_count >= repeats)
163                .unwrap_or(false)
164        {
165            // We deserve to draw something!
166
167            if boring {
168                // We're only here because of a timeout.
169                self.on_event(event::Event::Refresh);
170                self.process_pending_backend_calls();
171            }
172
173            self.refresh();
174        }
175
176        if boring {
177            std::thread::sleep(Duration::from_millis(INPUT_POLL_DELAY_MS));
178            self.boring_frame_count += 1;
179        }
180    }
181
182    /// Refresh the screen with the current view tree state.
183    pub fn refresh(&mut self) {
184        self.boring_frame_count = 0;
185
186        // Do we need to redraw every time?
187        // Probably, actually.
188        // TODO: Do we need to re-layout every time?
189        self.layout();
190
191        // TODO: Do we need to redraw every view every time?
192        // (Is this getting repetitive? :p)
193        self.draw();
194        self.backend.refresh();
195    }
196
197    /// Return the name of the backend used.
198    ///
199    /// Mostly used for debugging.
200    pub fn backend_name(&self) -> &str {
201        self.backend.name()
202    }
203
204    /// Performs a single step from the event loop.
205    ///
206    /// Useful if you need tighter control on the event loop.
207    /// Otherwise, [`run(&mut self)`] might be more convenient.
208    ///
209    /// Returns `true` if an input event or callback was received
210    /// during this step, and `false` otherwise.
211    ///
212    /// [`run(&mut self)`]: #method.run
213    pub fn step(&mut self) -> bool {
214        let received_something = self.process_events();
215        self.post_events(received_something);
216        received_something
217    }
218
219    /// Runs the event loop.
220    ///
221    /// It will wait for user input (key presses)
222    /// and trigger callbacks accordingly.
223    ///
224    /// Internally, it calls [`step(&mut self)`] until [`quit(&mut self)`] is
225    /// called.
226    ///
227    /// After this function returns, you can call it again and it will start a
228    /// new loop.
229    ///
230    /// [`step(&mut self)`]: #method.step
231    /// [`quit(&mut self)`]: #method.quit
232    pub fn run(&mut self) {
233        self.refresh();
234
235        // And the big event loop begins!
236        while self.is_running() {
237            self.step();
238        }
239    }
240}