mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-27 11:16:03 +00:00
Add event polling to Blt backend
Basically simulates a constant set_fps(30)
This commit is contained in:
parent
05e1212a50
commit
0b6e5b6ad4
@ -15,7 +15,7 @@ use std::collections::HashSet;
|
||||
use theme::{BaseColor, Color, ColorPair, Effect};
|
||||
use vec::Vec2;
|
||||
use chan;
|
||||
use std::thread;
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
enum ColorRole {
|
||||
Foreground,
|
||||
@ -23,28 +23,38 @@ enum ColorRole {
|
||||
}
|
||||
|
||||
pub struct Backend {
|
||||
}
|
||||
|
||||
struct InputParser {
|
||||
event_sink: chan::Sender<Event>,
|
||||
buttons_pressed: HashSet<MouseButton>,
|
||||
mouse_position: Vec2,
|
||||
}
|
||||
|
||||
impl InputParser {
|
||||
fn new(event_sink: chan::Sender<Event>) -> Self {
|
||||
InputParser {
|
||||
event_sink,
|
||||
impl Backend {
|
||||
pub fn init() -> Box<backend::Backend> {
|
||||
terminal::open("Cursive", 80, 24);
|
||||
terminal::set(terminal::config::Window::empty().resizeable(true));
|
||||
terminal::set(vec![
|
||||
terminal::config::InputFilter::Group {
|
||||
group: terminal::config::InputFilterGroup::Keyboard,
|
||||
both: false,
|
||||
},
|
||||
terminal::config::InputFilter::Group {
|
||||
group: terminal::config::InputFilterGroup::Mouse,
|
||||
both: true,
|
||||
},
|
||||
]);
|
||||
|
||||
let c = Backend {
|
||||
buttons_pressed: HashSet::new(),
|
||||
mouse_position: Vec2::zero(),
|
||||
}
|
||||
};
|
||||
|
||||
Box::new(c)
|
||||
}
|
||||
|
||||
fn parse_next(&mut self) {
|
||||
fn parse_next(&mut self) -> Option<Event> {
|
||||
|
||||
// TODO: we could add backend-specific controls here.
|
||||
// Ex: ctrl+mouse wheel cause window cellsize to change
|
||||
let event = if let Some(ev) = terminal::wait_event() {
|
||||
terminal::read_event().map(|ev| {
|
||||
match ev {
|
||||
BltEvent::Close => Event::Exit,
|
||||
BltEvent::Resize { .. } => Event::WindowResize,
|
||||
@ -94,10 +104,7 @@ impl InputParser {
|
||||
Event::Refresh
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Event::Refresh
|
||||
};
|
||||
self.event_sink.send(event);
|
||||
})
|
||||
}
|
||||
|
||||
fn blt_keycode_to_ev(
|
||||
@ -223,28 +230,6 @@ impl InputParser {
|
||||
}
|
||||
}
|
||||
|
||||
impl Backend {
|
||||
pub fn init() -> Box<backend::Backend> {
|
||||
terminal::open("Cursive", 80, 24);
|
||||
terminal::set(terminal::config::Window::empty().resizeable(true));
|
||||
terminal::set(vec![
|
||||
terminal::config::InputFilter::Group {
|
||||
group: terminal::config::InputFilterGroup::Keyboard,
|
||||
both: false,
|
||||
},
|
||||
terminal::config::InputFilter::Group {
|
||||
group: terminal::config::InputFilterGroup::Mouse,
|
||||
both: true,
|
||||
},
|
||||
]);
|
||||
|
||||
let c = Backend {};
|
||||
|
||||
Box::new(c)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
impl backend::Backend for Backend {
|
||||
fn finish(&mut self) {
|
||||
terminal::close();
|
||||
@ -320,14 +305,19 @@ impl backend::Backend for Backend {
|
||||
terminal::print_xy(pos.x as i32, pos.y as i32, text);
|
||||
}
|
||||
|
||||
fn start_input_thread(&mut self, event_sink: chan::Sender<Event>) {
|
||||
let mut parser = InputParser::new(event_sink);
|
||||
fn start_input_thread(&mut self, _event_sink: chan::Sender<Event>) {
|
||||
}
|
||||
|
||||
thread::spawn(move || {
|
||||
loop {
|
||||
parser.parse_next();
|
||||
fn prepare_input(&mut self, event_sink: &chan::Sender<Event>, timeout: Duration) {
|
||||
// Wait for up to `timeout_ms`.
|
||||
let start = Instant::now();
|
||||
while start.elapsed() < timeout {
|
||||
if let Some(event) = self.parse_next() {
|
||||
event_sink.send(event);
|
||||
return;
|
||||
}
|
||||
});
|
||||
}
|
||||
event_sink.send(Event::Refresh);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4,7 +4,7 @@ use theme;
|
||||
use event;
|
||||
use vec::Vec2;
|
||||
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
use chan;
|
||||
|
||||
@ -32,8 +32,11 @@ impl backend::Backend for Backend {
|
||||
(1, 1).into()
|
||||
}
|
||||
|
||||
fn start_input_thread(&mut self, event_sink: chan::Sender<event::Event>) {
|
||||
thread::spawn(move || event_sink.send(event::Event::Exit));
|
||||
fn start_input_thread(&mut self, _event_sink: chan::Sender<event::Event>) {
|
||||
}
|
||||
|
||||
fn prepare_input(&mut self, event_sink: &chan::Sender<event::Event>, _timeout: Duration) {
|
||||
event_sink.send(event::Event::Exit)
|
||||
}
|
||||
|
||||
fn print_at(&self, _: Vec2, _: &str) {}
|
||||
|
@ -14,6 +14,8 @@ use chan::Sender;
|
||||
|
||||
use vec::Vec2;
|
||||
|
||||
use std::time::Duration;
|
||||
|
||||
pub mod dummy;
|
||||
|
||||
pub mod termion;
|
||||
@ -29,8 +31,20 @@ pub trait Backend {
|
||||
/// This should clear any state in the terminal.
|
||||
fn finish(&mut self);
|
||||
|
||||
/// Starts a thread to collect input and send it to the given channel.
|
||||
fn start_input_thread(&mut self, event_sink: Sender<event::Event>);
|
||||
|
||||
/// Prepares the backend to collect input.
|
||||
///
|
||||
/// This is only required for non-thread-safe backends like BearLibTerminal
|
||||
/// where we cannot collect input in a separate thread.
|
||||
fn prepare_input(&mut self, event_sink: &Sender<event::Event>, timeout: Duration) {
|
||||
// Dummy implementation for most backends.
|
||||
// Little trick to avoid unused variables.
|
||||
let _ = event_sink;
|
||||
let _ = timeout;
|
||||
}
|
||||
|
||||
/// Refresh the screen.
|
||||
fn refresh(&mut self);
|
||||
|
||||
@ -40,9 +54,6 @@ pub trait Backend {
|
||||
/// Returns the screen size.
|
||||
fn screen_size(&self) -> Vec2;
|
||||
|
||||
// /// Gets a receiver for input events.
|
||||
// fn event_receiver(&mut self) -> Receiver<event::Event>;
|
||||
|
||||
/// Main method used for printing
|
||||
fn print_at(&self, pos: Vec2, text: &str);
|
||||
|
||||
|
@ -5,6 +5,7 @@ use event::{Callback, Event, EventResult};
|
||||
use printer::Printer;
|
||||
use std::any::Any;
|
||||
use std::collections::HashMap;
|
||||
use std::time::Duration;
|
||||
use std::path::Path;
|
||||
use theme;
|
||||
use vec::Vec2;
|
||||
@ -40,6 +41,7 @@ pub struct Cursive {
|
||||
cb_sink: chan::Sender<Box<CbFunc>>,
|
||||
|
||||
event_source: chan::Receiver<Event>,
|
||||
event_sink: chan::Sender<Event>,
|
||||
}
|
||||
|
||||
/// Describes one of the possible interruptions we should handle.
|
||||
@ -122,7 +124,7 @@ impl Cursive {
|
||||
let (cb_sink, cb_source) = chan::async();
|
||||
let (event_sink, event_source) = chan::async();
|
||||
|
||||
backend.start_input_thread(event_sink);
|
||||
backend.start_input_thread(event_sink.clone());
|
||||
|
||||
Cursive {
|
||||
fps: 0,
|
||||
@ -136,6 +138,7 @@ impl Cursive {
|
||||
cb_source,
|
||||
cb_sink,
|
||||
event_source,
|
||||
event_sink,
|
||||
backend: backend,
|
||||
}
|
||||
}
|
||||
@ -573,6 +576,8 @@ impl Cursive {
|
||||
let input_channel = &self.event_source;
|
||||
let cb_channel = &self.cb_source;
|
||||
|
||||
self.backend.prepare_input(&self.event_sink, Duration::from_millis(30));
|
||||
|
||||
if self.fps > 0 {
|
||||
let timeout = 1000 / self.fps;
|
||||
let timeout = chan::after_ms(timeout);
|
||||
|
Loading…
Reference in New Issue
Block a user