mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-27 19:26:09 +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 theme::{BaseColor, Color, ColorPair, Effect};
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
use chan;
|
use chan;
|
||||||
use std::thread;
|
use std::time::{Duration, Instant};
|
||||||
|
|
||||||
enum ColorRole {
|
enum ColorRole {
|
||||||
Foreground,
|
Foreground,
|
||||||
@ -23,28 +23,38 @@ enum ColorRole {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct Backend {
|
pub struct Backend {
|
||||||
}
|
|
||||||
|
|
||||||
struct InputParser {
|
|
||||||
event_sink: chan::Sender<Event>,
|
|
||||||
buttons_pressed: HashSet<MouseButton>,
|
buttons_pressed: HashSet<MouseButton>,
|
||||||
mouse_position: Vec2,
|
mouse_position: Vec2,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl InputParser {
|
impl Backend {
|
||||||
fn new(event_sink: chan::Sender<Event>) -> Self {
|
pub fn init() -> Box<backend::Backend> {
|
||||||
InputParser {
|
terminal::open("Cursive", 80, 24);
|
||||||
event_sink,
|
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(),
|
buttons_pressed: HashSet::new(),
|
||||||
mouse_position: Vec2::zero(),
|
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.
|
// TODO: we could add backend-specific controls here.
|
||||||
// Ex: ctrl+mouse wheel cause window cellsize to change
|
// 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 {
|
match ev {
|
||||||
BltEvent::Close => Event::Exit,
|
BltEvent::Close => Event::Exit,
|
||||||
BltEvent::Resize { .. } => Event::WindowResize,
|
BltEvent::Resize { .. } => Event::WindowResize,
|
||||||
@ -94,10 +104,7 @@ impl InputParser {
|
|||||||
Event::Refresh
|
Event::Refresh
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
})
|
||||||
Event::Refresh
|
|
||||||
};
|
|
||||||
self.event_sink.send(event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn blt_keycode_to_ev(
|
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 {
|
impl backend::Backend for Backend {
|
||||||
fn finish(&mut self) {
|
fn finish(&mut self) {
|
||||||
terminal::close();
|
terminal::close();
|
||||||
@ -320,14 +305,19 @@ impl backend::Backend for Backend {
|
|||||||
terminal::print_xy(pos.x as i32, pos.y as i32, text);
|
terminal::print_xy(pos.x as i32, pos.y as i32, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_input_thread(&mut self, event_sink: chan::Sender<Event>) {
|
fn start_input_thread(&mut self, _event_sink: chan::Sender<Event>) {
|
||||||
let mut parser = InputParser::new(event_sink);
|
}
|
||||||
|
|
||||||
thread::spawn(move || {
|
fn prepare_input(&mut self, event_sink: &chan::Sender<Event>, timeout: Duration) {
|
||||||
loop {
|
// Wait for up to `timeout_ms`.
|
||||||
parser.parse_next();
|
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 event;
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
|
|
||||||
use std::thread;
|
use std::time::Duration;
|
||||||
|
|
||||||
use chan;
|
use chan;
|
||||||
|
|
||||||
@ -32,8 +32,11 @@ impl backend::Backend for Backend {
|
|||||||
(1, 1).into()
|
(1, 1).into()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn start_input_thread(&mut self, event_sink: chan::Sender<event::Event>) {
|
fn start_input_thread(&mut self, _event_sink: chan::Sender<event::Event>) {
|
||||||
thread::spawn(move || event_sink.send(event::Event::Exit));
|
}
|
||||||
|
|
||||||
|
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) {}
|
fn print_at(&self, _: Vec2, _: &str) {}
|
||||||
|
@ -14,6 +14,8 @@ use chan::Sender;
|
|||||||
|
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
|
|
||||||
|
use std::time::Duration;
|
||||||
|
|
||||||
pub mod dummy;
|
pub mod dummy;
|
||||||
|
|
||||||
pub mod termion;
|
pub mod termion;
|
||||||
@ -29,8 +31,20 @@ pub trait Backend {
|
|||||||
/// This should clear any state in the terminal.
|
/// This should clear any state in the terminal.
|
||||||
fn finish(&mut self);
|
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>);
|
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.
|
/// Refresh the screen.
|
||||||
fn refresh(&mut self);
|
fn refresh(&mut self);
|
||||||
|
|
||||||
@ -40,9 +54,6 @@ pub trait Backend {
|
|||||||
/// Returns the screen size.
|
/// Returns the screen size.
|
||||||
fn screen_size(&self) -> Vec2;
|
fn screen_size(&self) -> Vec2;
|
||||||
|
|
||||||
// /// Gets a receiver for input events.
|
|
||||||
// fn event_receiver(&mut self) -> Receiver<event::Event>;
|
|
||||||
|
|
||||||
/// Main method used for printing
|
/// Main method used for printing
|
||||||
fn print_at(&self, pos: Vec2, text: &str);
|
fn print_at(&self, pos: Vec2, text: &str);
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ use event::{Callback, Event, EventResult};
|
|||||||
use printer::Printer;
|
use printer::Printer;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::time::Duration;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use theme;
|
use theme;
|
||||||
use vec::Vec2;
|
use vec::Vec2;
|
||||||
@ -40,6 +41,7 @@ pub struct Cursive {
|
|||||||
cb_sink: chan::Sender<Box<CbFunc>>,
|
cb_sink: chan::Sender<Box<CbFunc>>,
|
||||||
|
|
||||||
event_source: chan::Receiver<Event>,
|
event_source: chan::Receiver<Event>,
|
||||||
|
event_sink: chan::Sender<Event>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Describes one of the possible interruptions we should handle.
|
/// Describes one of the possible interruptions we should handle.
|
||||||
@ -122,7 +124,7 @@ impl Cursive {
|
|||||||
let (cb_sink, cb_source) = chan::async();
|
let (cb_sink, cb_source) = chan::async();
|
||||||
let (event_sink, event_source) = chan::async();
|
let (event_sink, event_source) = chan::async();
|
||||||
|
|
||||||
backend.start_input_thread(event_sink);
|
backend.start_input_thread(event_sink.clone());
|
||||||
|
|
||||||
Cursive {
|
Cursive {
|
||||||
fps: 0,
|
fps: 0,
|
||||||
@ -136,6 +138,7 @@ impl Cursive {
|
|||||||
cb_source,
|
cb_source,
|
||||||
cb_sink,
|
cb_sink,
|
||||||
event_source,
|
event_source,
|
||||||
|
event_sink,
|
||||||
backend: backend,
|
backend: backend,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -573,6 +576,8 @@ impl Cursive {
|
|||||||
let input_channel = &self.event_source;
|
let input_channel = &self.event_source;
|
||||||
let cb_channel = &self.cb_source;
|
let cb_channel = &self.cb_source;
|
||||||
|
|
||||||
|
self.backend.prepare_input(&self.event_sink, Duration::from_millis(30));
|
||||||
|
|
||||||
if self.fps > 0 {
|
if self.fps > 0 {
|
||||||
let timeout = 1000 / self.fps;
|
let timeout = 1000 / self.fps;
|
||||||
let timeout = chan::after_ms(timeout);
|
let timeout = chan::after_ms(timeout);
|
||||||
|
Loading…
Reference in New Issue
Block a user