Cursive::new now takes the backend as argument

This commit is contained in:
Alexandre Bury 2018-04-01 16:39:03 -07:00
parent 76d340f11d
commit 126530b9a9
43 changed files with 340 additions and 250 deletions

View File

@ -4,11 +4,5 @@ rust:
- stable - stable
- nightly - nightly
script: script:
- cargo build --verbose - cargo build --verbose --features "pancurses-backend termion-backend"
- cargo test --verbose - cargo test --verbose --features "pancurses-backend termion-backend"
-
- cargo build --verbose --features=pancurses-backend --no-default-features
- cargo test --verbose --features=pancurses-backend --no-default-features
-
- cargo build --verbose --features=termion-backend --no-default-features
- cargo test --verbose --features=termion-backend --no-default-features

View File

@ -12,7 +12,7 @@ use cursive::Cursive;
use cursive::views::TextView; use cursive::views::TextView;
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
siv.add_global_callback('q', |s| s.quit()); siv.add_global_callback('q', |s| s.quit());
@ -80,7 +80,7 @@ extern crate cursive;
use cursive::Cursive; use cursive::Cursive;
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
siv.run(); siv.run();
} }
@ -117,7 +117,7 @@ extern crate cursive;
use cursive::Cursive; use cursive::Cursive;
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
siv.add_global_callback('q', |s| s.quit()); siv.add_global_callback('q', |s| s.quit());
@ -159,7 +159,7 @@ use cursive::Cursive;
use cursive::views::TextView; use cursive::views::TextView;
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
siv.add_global_callback('q', |s| s.quit()); siv.add_global_callback('q', |s| s.quit());

View File

@ -12,7 +12,7 @@ use cursive::Cursive;
use cursive::views::Dialog; use cursive::views::Dialog;
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
siv.add_layer(Dialog::text("This is a survey!\nPress <Next> when you're ready.") siv.add_layer(Dialog::text("This is a survey!\nPress <Next> when you're ready.")
.title("Important survey") .title("Important survey")
@ -51,7 +51,7 @@ extern crate cursive;
use cursive::Cursive; use cursive::Cursive;
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
siv.run(); siv.run();
} }
@ -74,7 +74,7 @@ use cursive::views::Dialog;
use cursive::views::TextView; use cursive::views::TextView;
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
siv.add_layer(Dialog::around(TextView::new("..."))); siv.add_layer(Dialog::around(TextView::new("...")));
@ -135,7 +135,7 @@ use cursive::Cursive;
use cursive::views::Dialog; use cursive::views::Dialog;
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
siv.add_layer(Dialog::text("This is a survey!\nPress <Next> when you're ready.") siv.add_layer(Dialog::text("This is a survey!\nPress <Next> when you're ready.")
.title("Important survey") .title("Important survey")

View File

@ -17,7 +17,7 @@ use cursive::views::{Button, Dialog, DummyView, EditView,
use cursive::traits::*; use cursive::traits::*;
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
let select = SelectView::<String>::new() let select = SelectView::<String>::new()
.on_submit(on_submit) .on_submit(on_submit)

View File

@ -17,7 +17,7 @@ use cursive::views::Canvas;
// 256 colors. // 256 colors.
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
siv.add_layer(Canvas::new(()).with_draw(draw).fixed_size((20, 10))); siv.add_layer(Canvas::new(()).with_draw(draw).fixed_size((20, 10)));

View File

@ -5,7 +5,7 @@ use cursive::views::{Dialog, TextView};
fn main() { fn main() {
// Creates the cursive root - required for every application. // Creates the cursive root - required for every application.
let mut siv = Cursive::new(); let mut siv = Cursive::default();
// Creates a dialog with a single "Quit" button // Creates a dialog with a single "Quit" button
siv.add_layer( siv.add_layer(

View File

@ -5,7 +5,7 @@ use cursive::traits::*;
use cursive::views::{Dialog, EditView, TextView}; use cursive::views::{Dialog, EditView, TextView};
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
// Create a dialog with an edit text and a button. // Create a dialog with an edit text and a button.
// The user can either hit the <Ok> button, // The user can either hit the <Ok> button,

View File

@ -4,7 +4,7 @@ use cursive::Cursive;
use cursive::views::TextView; use cursive::views::TextView;
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
// We can quit by pressing `q` // We can quit by pressing `q`
siv.add_global_callback('q', Cursive::quit); siv.add_global_callback('q', Cursive::quit);

View File

@ -8,7 +8,7 @@ use cursive::traits::*;
// This is a handy way to check the input received by cursive. // This is a handy way to check the input received by cursive.
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
siv.add_layer(KeyCodeView::new(10).full_width().fixed_height(10)); siv.add_layer(KeyCodeView::new(10).full_width().fixed_height(10));
siv.run(); siv.run();

View File

@ -8,7 +8,7 @@ use cursive::views::{Dialog, DummyView, LinearLayout, TextView};
// This example uses a LinearLayout to stick multiple views next to each other. // This example uses a LinearLayout to stick multiple views next to each other.
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
// Some description text // Some description text
let text = "This is a very simple example of linear layout. Two views \ let text = "This is a very simple example of linear layout. Two views \

View File

@ -10,7 +10,7 @@ use cursive::views::{Checkbox, Dialog, EditView, LinearLayout, ListView,
// ListView can be used to build forms, with a list of inputs. // ListView can be used to build forms, with a list of inputs.
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
siv.add_layer( siv.add_layer(
Dialog::new() Dialog::new()

View File

@ -14,7 +14,7 @@ use std::time::Duration;
fn main() { fn main() {
// As usual, create the Cursive root // As usual, create the Cursive root
let mut siv = Cursive::new(); let mut siv = Cursive::default();
// We want to refresh the page even when no input is given. // We want to refresh the page even when no input is given.
siv.set_fps(10); siv.set_fps(10);

View File

@ -9,7 +9,7 @@ fn main() {
// Read some long text from a file. // Read some long text from a file.
let content = include_str!("../assets/lorem.txt"); let content = include_str!("../assets/lorem.txt");
let mut siv = Cursive::new(); let mut siv = Cursive::default();
// We can quit by pressing q // We can quit by pressing q
siv.add_global_callback('q', |s| s.quit()); siv.add_global_callback('q', |s| s.quit());

View File

@ -9,7 +9,7 @@ use cursive::utils::markup::StyledString;
use cursive::views::{Dialog, TextView}; use cursive::views::{Dialog, TextView};
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
let mut styled = StyledString::plain("Isn't "); let mut styled = StyledString::plain("Isn't ");
styled.append(StyledString::styled("that ", Color::Dark(BaseColor::Red))); styled.append(StyledString::styled("that ", Color::Dark(BaseColor::Red)));

View File

@ -11,7 +11,7 @@ use std::sync::atomic::{AtomicUsize, Ordering};
// application. // application.
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
// We'll use a counter to name new files. // We'll use a counter to name new files.
let counter = AtomicUsize::new(1); let counter = AtomicUsize::new(1);

View File

@ -12,7 +12,7 @@ use cursive::vec::Vec2;
use cursive::views::{Button, Dialog, LinearLayout, Panel, SelectView}; use cursive::views::{Button, Dialog, LinearLayout, Panel, SelectView};
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
siv.add_layer( siv.add_layer(
Dialog::new() Dialog::new()

View File

@ -8,7 +8,7 @@ use cursive::views::{Dialog, OnEventView, TextView};
// This example modifies a view after creation. // This example modifies a view after creation.
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
let content = "Press Q to quit the application.\n\nPress P to open the \ let content = "Press Q to quit the application.\n\nPress P to open the \
popup."; popup.";

View File

@ -22,7 +22,7 @@ fn move_top(c: &mut Cursive, x_in: isize, y_in: isize) {
} }
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
siv.set_fps(60); siv.set_fps(60);
// We can quit by pressing `q` // We can quit by pressing `q`

View File

@ -17,7 +17,7 @@ use std::time::Duration;
// "ticked" to indicate progress. // "ticked" to indicate progress.
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
// We'll start slowly with a simple start button... // We'll start slowly with a simple start button...
siv.add_layer( siv.add_layer(

View File

@ -6,7 +6,7 @@ use cursive::views::{Dialog, DummyView, LinearLayout, RadioGroup};
// This example uses radio buttons. // This example uses radio buttons.
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
// We need to pre-create the groups for our RadioButtons. // We need to pre-create the groups for our RadioButtons.
let mut color_group: RadioGroup<String> = RadioGroup::new(); let mut color_group: RadioGroup<String> = RadioGroup::new();

View File

@ -7,7 +7,7 @@ use cursive::views::{Dialog, EditView, LinearLayout, TextView};
// This example shows a way to access multiple views at the same time. // This example shows a way to access multiple views at the same time.
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
// Create a dialog with 2 edit fields, and a text view. // Create a dialog with 2 edit fields, and a text view.
// The text view indicates when the 2 fields content match. // The text view indicates when the 2 fields content match.

View File

@ -33,7 +33,7 @@ fn main() {
Some(EventResult::Consumed(None)) Some(EventResult::Consumed(None))
}); });
let mut siv = Cursive::new(); let mut siv = Cursive::default();
// Let's add a BoxView to keep the list at a reasonable size // Let's add a BoxView to keep the list at a reasonable size
// (it can scroll anyway). // (it can scroll anyway).

View File

@ -5,7 +5,7 @@ use cursive::traits::*;
use cursive::views::{Dialog, SliderView}; use cursive::views::{Dialog, SliderView};
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
siv.add_global_callback('q', |s| s.quit()); siv.add_global_callback('q', |s| s.quit());

View File

@ -9,7 +9,7 @@ use cursive::views::TextView;
// This way, it looks more natural. // This way, it looks more natural.
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
let theme = custom_theme_from_cursive(&siv); let theme = custom_theme_from_cursive(&siv);
siv.set_theme(theme); siv.set_theme(theme);

View File

@ -6,7 +6,7 @@ use cursive::traits::*;
use cursive::views::{Dialog, EditView, OnEventView, TextArea}; use cursive::views::{Dialog, EditView, OnEventView, TextArea};
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
// The main dialog will just have a textarea. // The main dialog will just have a textarea.
// Its size expand automatically with the content. // Its size expand automatically with the content.

View File

@ -4,7 +4,7 @@ use cursive::Cursive;
use cursive::views::{Dialog, TextView}; use cursive::views::{Dialog, TextView};
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
// You can load a theme from a file at runtime for fast development. // You can load a theme from a file at runtime for fast development.
siv.load_theme_file("assets/style.toml").unwrap(); siv.load_theme_file("assets/style.toml").unwrap();

View File

@ -5,7 +5,7 @@ use cursive::theme::{BaseColor, BorderStyle, Color, ColorStyle};
use cursive::views::{Dialog, EditView, LinearLayout, TextView}; use cursive::views::{Dialog, EditView, LinearLayout, TextView};
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::default();
let layout = LinearLayout::vertical() let layout = LinearLayout::vertical()
.child(TextView::new("This is a dynamic theme example!")) .child(TextView::new("This is a dynamic theme example!"))

View File

@ -15,12 +15,34 @@ enum ColorRole {
Background, Background,
} }
pub struct Concrete { pub struct Backend {
mouse_position: Vec2, mouse_position: Vec2,
buttons_pressed: HashSet<MouseButton>, buttons_pressed: HashSet<MouseButton>,
} }
impl Concrete { impl Backend {
pub fn init() -> Box<Self> {
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 {
mouse_position: Vec2::zero(),
buttons_pressed: HashSet::new(),
};
Box::new(c)
}
fn blt_keycode_to_ev( fn blt_keycode_to_ev(
&mut self, kc: KeyCode, shift: bool, ctrl: bool &mut self, kc: KeyCode, shift: bool, ctrl: bool
) -> Event { ) -> Event {
@ -144,29 +166,7 @@ impl Concrete {
} }
} }
impl backend::Backend for Concrete { impl backend::Backend for Backend {
fn init() -> Box<Self> {
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 = Concrete {
mouse_position: Vec2::zero(),
buttons_pressed: HashSet::new(),
};
Box::new(c)
}
fn finish(&mut self) { fn finish(&mut self) {
terminal::close(); terminal::close();
} }

View File

@ -3,14 +3,10 @@ use std::collections::HashMap;
use theme::{BaseColor, Color}; use theme::{BaseColor, Color};
#[cfg(feature = "ncurses")] #[cfg(feature = "ncurses")]
mod n; pub mod n;
#[cfg(feature = "ncurses")]
pub use self::n::*;
#[cfg(feature = "pancurses")] #[cfg(feature = "pancurses")]
mod pan; pub mod pan;
#[cfg(feature = "pancurses")]
pub use self::pan::*;
fn split_i32(code: i32) -> Vec<u8> { fn split_i32(code: i32) -> Vec<u8> {
(0..4).map(|i| ((code >> (8 * i)) & 0xFF) as u8).collect() (0..4).map(|i| ((code >> (8 * i)) & 0xFF) as u8).collect()

View File

@ -11,7 +11,7 @@ use theme::{Color, ColorPair, Effect};
use utf8; use utf8;
use vec::Vec2; use vec::Vec2;
pub struct Concrete { pub struct Backend {
current_style: Cell<ColorPair>, current_style: Cell<ColorPair>,
pairs: RefCell<HashMap<ColorPair, i16>>, pairs: RefCell<HashMap<ColorPair, i16>>,
@ -21,7 +21,56 @@ pub struct Concrete {
event_queue: Vec<Event>, event_queue: Vec<Event>,
} }
impl Concrete { impl Backend {
pub fn init() -> Box<backend::Backend> {
// Change the locale.
// For some reasons it's mandatory to get some UTF-8 support.
ncurses::setlocale(ncurses::LcCategory::all, "");
// The delay is the time ncurses wait after pressing ESC
// to see if it's an escape sequence.
// Default delay is way too long. 25 is imperceptible yet works fine.
::std::env::set_var("ESCDELAY", "25");
ncurses::initscr();
ncurses::keypad(ncurses::stdscr(), true);
// This disables mouse click detection,
// and provides 0-delay access to mouse presses.
ncurses::mouseinterval(0);
// Listen to all mouse events.
ncurses::mousemask(
(ncurses::ALL_MOUSE_EVENTS | ncurses::REPORT_MOUSE_POSITION)
as mmask_t,
None,
);
ncurses::noecho();
ncurses::cbreak();
ncurses::start_color();
// Pick up background and text color from the terminal theme.
ncurses::use_default_colors();
// No cursor
ncurses::curs_set(ncurses::CURSOR_VISIBILITY::CURSOR_INVISIBLE);
// This asks the terminal to provide us with mouse drag events
// (Mouse move when a button is pressed).
// Replacing 1002 with 1003 would give us ANY mouse move.
print!("\x1B[?1002h");
stdout().flush().expect("could not flush stdout");
let c = Backend {
current_style: Cell::new(ColorPair::from_256colors(0, 0)),
pairs: RefCell::new(HashMap::new()),
last_mouse_button: None,
event_queue: Vec::new(),
key_codes: initialize_keymap(),
};
Box::new(c)
}
/// Save a new color pair. /// Save a new color pair.
fn insert_color( fn insert_color(
&self, pairs: &mut HashMap<ColorPair, i16>, pair: ColorPair &self, pairs: &mut HashMap<ColorPair, i16>, pair: ColorPair
@ -149,56 +198,7 @@ impl Concrete {
} }
} }
impl backend::Backend for Concrete { impl backend::Backend for Backend {
fn init() -> Box<Self> {
// Change the locale.
// For some reasons it's mandatory to get some UTF-8 support.
ncurses::setlocale(ncurses::LcCategory::all, "");
// The delay is the time ncurses wait after pressing ESC
// to see if it's an escape sequence.
// Default delay is way too long. 25 is imperceptible yet works fine.
::std::env::set_var("ESCDELAY", "25");
ncurses::initscr();
ncurses::keypad(ncurses::stdscr(), true);
// This disables mouse click detection,
// and provides 0-delay access to mouse presses.
ncurses::mouseinterval(0);
// Listen to all mouse events.
ncurses::mousemask(
(ncurses::ALL_MOUSE_EVENTS | ncurses::REPORT_MOUSE_POSITION)
as mmask_t,
None,
);
ncurses::noecho();
ncurses::cbreak();
ncurses::start_color();
// Pick up background and text color from the terminal theme.
ncurses::use_default_colors();
// No cursor
ncurses::curs_set(ncurses::CURSOR_VISIBILITY::CURSOR_INVISIBLE);
// This asks the terminal to provide us with mouse drag events
// (Mouse move when a button is pressed).
// Replacing 1002 with 1003 would give us ANY mouse move.
print!("\x1B[?1002h");
stdout().flush().expect("could not flush stdout");
let c = Concrete {
current_style: Cell::new(ColorPair::from_256colors(0, 0)),
pairs: RefCell::new(HashMap::new()),
last_mouse_button: None,
event_queue: Vec::new(),
key_codes: initialize_keymap(),
};
Box::new(c)
}
fn screen_size(&self) -> (usize, usize) { fn screen_size(&self) -> (usize, usize) {
let mut x: i32 = 0; let mut x: i32 = 0;
let mut y: i32 = 0; let mut y: i32 = 0;

View File

@ -10,7 +10,7 @@ use std::io::{stdout, Write};
use theme::{Color, ColorPair, Effect}; use theme::{Color, ColorPair, Effect};
use vec::Vec2; use vec::Vec2;
pub struct Concrete { pub struct Backend {
// Used // Used
current_style: Cell<ColorPair>, current_style: Cell<ColorPair>,
pairs: RefCell<HashMap<ColorPair, i32>>, pairs: RefCell<HashMap<ColorPair, i32>>,
@ -24,7 +24,41 @@ pub struct Concrete {
window: pancurses::Window, window: pancurses::Window,
} }
impl Concrete { impl Backend {
pub fn init() -> Box<Self> {
::std::env::set_var("ESCDELAY", "25");
let window = pancurses::initscr();
window.keypad(true);
pancurses::noecho();
pancurses::cbreak();
pancurses::start_color();
pancurses::use_default_colors();
pancurses::curs_set(0);
pancurses::mouseinterval(0);
pancurses::mousemask(
pancurses::ALL_MOUSE_EVENTS | pancurses::REPORT_MOUSE_POSITION,
::std::ptr::null_mut(),
);
// This asks the terminal to provide us with mouse drag events
// (Mouse move when a button is pressed).
// Replacing 1002 with 1003 would give us ANY mouse move.
print!("\x1B[?1002h");
stdout().flush().expect("could not flush stdout");
let c = Backend {
current_style: Cell::new(ColorPair::from_256colors(0, 0)),
pairs: RefCell::new(HashMap::new()),
window: window,
last_mouse_button: None,
event_queue: Vec::new(),
key_codes: initialize_keymap(),
};
Box::new(c)
}
/// Save a new color pair. /// Save a new color pair.
fn insert_color( fn insert_color(
&self, pairs: &mut HashMap<ColorPair, i32>, pair: ColorPair &self, pairs: &mut HashMap<ColorPair, i32>, pair: ColorPair
@ -132,41 +166,7 @@ impl Concrete {
} }
} }
impl backend::Backend for Concrete { impl backend::Backend for Backend {
fn init() -> Box<Self> {
::std::env::set_var("ESCDELAY", "25");
let window = pancurses::initscr();
window.keypad(true);
pancurses::noecho();
pancurses::cbreak();
pancurses::start_color();
pancurses::use_default_colors();
pancurses::curs_set(0);
pancurses::mouseinterval(0);
pancurses::mousemask(
pancurses::ALL_MOUSE_EVENTS | pancurses::REPORT_MOUSE_POSITION,
::std::ptr::null_mut(),
);
// This asks the terminal to provide us with mouse drag events
// (Mouse move when a button is pressed).
// Replacing 1002 with 1003 would give us ANY mouse move.
print!("\x1B[?1002h");
stdout().flush().expect("could not flush stdout");
let c = Concrete {
current_style: Cell::new(ColorPair::from_256colors(0, 0)),
pairs: RefCell::new(HashMap::new()),
window: window,
last_mouse_button: None,
event_queue: Vec::new(),
key_codes: initialize_keymap(),
};
Box::new(c)
}
fn screen_size(&self) -> (usize, usize) { fn screen_size(&self) -> (usize, usize) {
let (y, x) = self.window.get_max_yx(); let (y, x) = self.window.get_max_yx();
(x as usize, y as usize) (x as usize, y as usize)

48
src/backend/dummy.rs Normal file
View File

@ -0,0 +1,48 @@
//! Dummy backend
use backend;
use theme;
use event;
pub struct Backend;
impl Backend {
pub fn init() -> Box<backend::Backend>
where
Self: Sized,
{
Box::new(Backend)
}
}
impl backend::Backend for Backend {
fn finish(&mut self) {}
fn refresh(&mut self) {}
fn has_colors(&self) -> bool {
false
}
fn screen_size(&self) -> (usize, usize) {
(1, 1)
}
fn poll_event(&mut self) -> event::Event {
event::Event::Exit
}
fn print_at(&self, _: (usize, usize), _: &str) {}
fn clear(&self, _: theme::Color) {}
fn set_refresh_rate(&mut self, _: u32) {}
// This sets the Colours and returns the previous colours
// to allow you to set them back when you're done.
fn set_color(&self, colors: theme::ColorPair) -> theme::ColorPair {
colors
}
fn set_effect(&self, _: theme::Effect) {}
fn unset_effect(&self, _: theme::Effect) {}
}

View File

@ -1,22 +1,20 @@
use event; use event;
use theme; use theme;
#[cfg(feature = "termion")] pub mod dummy;
mod termion;
#[cfg(feature = "bear-lib-terminal")]
mod blt;
#[cfg(any(feature = "ncurses", feature = "pancurses"))]
mod curses;
#[cfg(feature = "bear-lib-terminal")] /// Backend using the pure-rust termion library.
pub use self::blt::*;
#[cfg(any(feature = "ncurses", feature = "pancurses"))]
pub use self::curses::*;
#[cfg(feature = "termion")] #[cfg(feature = "termion")]
pub use self::termion::*; pub mod termion;
/// Backend using BearLibTerminal
#[cfg(feature = "bear-lib-terminal")]
pub mod blt;
#[cfg(any(feature = "ncurses", feature = "pancurses"))]
pub mod curses;
pub trait Backend { pub trait Backend {
fn init() -> Box<Self> where Self: Sized;
// TODO: take `self` by value? // TODO: take `self` by value?
// Or implement Drop? // Or implement Drop?
fn finish(&mut self); fn finish(&mut self);

View File

@ -20,7 +20,7 @@ use std::thread;
use theme; use theme;
use vec::Vec2; use vec::Vec2;
pub struct Concrete { pub struct Backend {
terminal: AlternateScreen<MouseTerminal<RawTerminal<Stdout>>>, terminal: AlternateScreen<MouseTerminal<RawTerminal<Stdout>>>,
current_style: Cell<theme::ColorPair>, current_style: Cell<theme::ColorPair>,
input: chan::Receiver<TEvent>, input: chan::Receiver<TEvent>,
@ -56,7 +56,39 @@ impl Effectable for theme::Effect {
} }
} }
impl Concrete { impl Backend {
pub fn init() -> Box<Self> {
print!("{}", termion::cursor::Hide);
let resize = chan_signal::notify(&[chan_signal::Signal::WINCH]);
// TODO: lock stdout
let terminal = AlternateScreen::from(MouseTerminal::from(
::std::io::stdout().into_raw_mode().unwrap(),
));
let (sender, receiver) = chan::async();
thread::spawn(move || {
for key in ::std::io::stdin().events() {
if let Ok(key) = key {
sender.send(key)
}
}
});
let c = Backend {
terminal: terminal,
current_style: Cell::new(theme::ColorPair::from_256colors(0, 0)),
input: receiver,
resize: resize,
timeout: None,
last_button: None,
};
Box::new(c)
}
fn apply_colors(&self, colors: theme::ColorPair) { fn apply_colors(&self, colors: theme::ColorPair) {
with_color(&colors.front, |c| print!("{}", tcolor::Fg(c))); with_color(&colors.front, |c| print!("{}", tcolor::Fg(c)));
with_color(&colors.back, |c| print!("{}", tcolor::Bg(c))); with_color(&colors.back, |c| print!("{}", tcolor::Bg(c)));
@ -136,39 +168,7 @@ impl Concrete {
} }
} }
impl backend::Backend for Concrete { impl backend::Backend for Backend {
fn init() -> Box<Self> {
print!("{}", termion::cursor::Hide);
let resize = chan_signal::notify(&[chan_signal::Signal::WINCH]);
// TODO: lock stdout
let terminal = AlternateScreen::from(MouseTerminal::from(
::std::io::stdout().into_raw_mode().unwrap(),
));
let (sender, receiver) = chan::async();
thread::spawn(move || {
for key in ::std::io::stdin().events() {
if let Ok(key) = key {
sender.send(key)
}
}
});
let c = Concrete {
terminal: terminal,
current_style: Cell::new(theme::ColorPair::from_256colors(0, 0)),
input: receiver,
resize: resize,
timeout: None,
last_button: None,
};
Box::new(c)
}
fn finish(&mut self) { fn finish(&mut self) {
print!("{}{}", termion::cursor::Show, termion::cursor::Goto(1, 1)); print!("{}{}", termion::cursor::Show, termion::cursor::Goto(1, 1));
print!( print!(

View File

@ -1,5 +1,4 @@
use backend; use backend;
use backend::Backend;
use direction; use direction;
use event::{Callback, Event, EventResult}; use event::{Callback, Event, EventResult};
use printer::Printer; use printer::Printer;
@ -33,6 +32,34 @@ impl<F: FnOnce(&mut Cursive) -> () + Send> CbFunc for F {
} }
} }
#[cfg(feature = "termion")]
impl Default for Cursive {
fn default() -> Self {
Self::termion()
}
}
#[cfg(all(not(feature = "termion"), feature = "pancurses"))]
impl Default for Cursive {
fn default() -> Self {
Self::pancurses()
}
}
#[cfg(all(not(feature = "termion"), not(feature = "pancurses"), feature = "bear-lib-terminal"))]
impl Default for Cursive {
fn default() -> Self {
Self::blt()
}
}
#[cfg(all(not(feature = "termion"), not(feature = "pancurses"), not(feature = "bear-lib-terminal"), feature = "ncurses"))]
impl Default for Cursive {
fn default() -> Self {
Self::ncurses()
}
}
/// Central part of the cursive library. /// Central part of the cursive library.
/// ///
/// It initializes ncurses on creation and cleans up on drop. /// It initializes ncurses on creation and cleans up on drop.
@ -60,13 +87,9 @@ pub struct Cursive {
cb_sink: mpsc::Sender<Box<CbFunc>>, cb_sink: mpsc::Sender<Box<CbFunc>>,
} }
new_default!(Cursive);
impl Cursive { impl Cursive {
/// Creates a new Cursive root, and initialize the back-end. /// Creates a new Cursive root, and initialize the back-end.
pub fn new() -> Self { pub fn new(backend: Box<backend::Backend>) -> Self {
let backend = backend::Concrete::init();
let theme = theme::load_default(); let theme = theme::load_default();
// theme.activate(&mut backend); // theme.activate(&mut backend);
// let theme = theme::load_theme("assets/style.toml").unwrap(); // let theme = theme::load_theme("assets/style.toml").unwrap();
@ -87,6 +110,37 @@ impl Cursive {
} }
} }
/// Creates a new Cursive root using a ncurses backend.
#[cfg(feature = "ncurses")]
pub fn ncurses() -> Self {
Self::new(backend::curses::n::Backend::init())
}
/// Creates a new Cursive root using a pancurses backend.
#[cfg(feature = "pancurses")]
pub fn pancurses() -> Self {
Self::new(backend::curses::pan::Backend::init())
}
/// Creates a new Cursive root using a termion backend.
#[cfg(feature = "termion")]
pub fn termion() -> Self {
Self::new(backend::termion::Backend::init())
}
/// Creates a new Cursive root using a bear-lib-terminal backend.
#[cfg(feature = "bear-lib-terminal")]
pub fn blt() -> Self {
Self::new(backend::blt::Backend::init())
}
/// Creates a new Cursive root using a dummy backend.
///
/// Nothing will be output. This is mostly here for tests.
pub fn dummy() -> Self {
Self::new(backend::dummy::Backend::init())
}
/// Returns a sink for asynchronous callbacks. /// Returns a sink for asynchronous callbacks.
/// ///
/// Returns the sender part of a channel, that allows to send /// Returns the sender part of a channel, that allows to send
@ -100,11 +154,11 @@ impl Cursive {
/// ///
/// # Examples /// # Examples
/// ///
/// ```rust,no_run /// ```rust
/// # extern crate cursive; /// # extern crate cursive;
/// # use cursive::*; /// # use cursive::*;
/// # fn main() { /// # fn main() {
/// let mut siv = Cursive::new(); /// let mut siv = Cursive::dummy();
/// siv.set_fps(10); /// siv.set_fps(10);
/// ///
/// // quit() will be called during the next event cycle /// // quit() will be called during the next event cycle
@ -136,7 +190,7 @@ impl Cursive {
/// ///
/// # Examples /// # Examples
/// ///
/// ```rust,no_run /// ```rust
/// # extern crate cursive; /// # extern crate cursive;
/// # /// #
/// # use cursive::{Cursive, event}; /// # use cursive::{Cursive, event};
@ -145,7 +199,7 @@ impl Cursive {
/// # use cursive::menu::*; /// # use cursive::menu::*;
/// # /// #
/// # fn main() { /// # fn main() {
/// let mut siv = Cursive::new(); /// let mut siv = Cursive::dummy();
/// ///
/// siv.menubar() /// siv.menubar()
/// .add_subtree("File", /// .add_subtree("File",
@ -289,13 +343,13 @@ impl Cursive {
/// ///
/// # Examples /// # Examples
/// ///
/// ```rust,no_run /// ```rust
/// # extern crate cursive; /// # extern crate cursive;
/// # use cursive::{Cursive, views, view}; /// # use cursive::{Cursive, views, view};
/// # use cursive::traits::*; /// # use cursive::traits::*;
/// # fn main() { /// # fn main() {
/// fn main() { /// fn main() {
/// let mut siv = Cursive::new(); /// let mut siv = Cursive::dummy();
/// ///
/// siv.add_layer(views::TextView::new("Text #1").with_id("text")); /// siv.add_layer(views::TextView::new("Text #1").with_id("text"));
/// ///
@ -327,12 +381,12 @@ impl Cursive {
/// ///
/// # Examples /// # Examples
/// ///
/// ```rust,no_run /// ```rust
/// # extern crate cursive; /// # extern crate cursive;
/// # use cursive::{Cursive, views}; /// # use cursive::{Cursive, views};
/// # use cursive::traits::*; /// # use cursive::traits::*;
/// # fn main() { /// # fn main() {
/// let mut siv = Cursive::new(); /// let mut siv = Cursive::dummy();
/// ///
/// siv.add_layer(views::TextView::new("Text #1") /// siv.add_layer(views::TextView::new("Text #1")
/// .with_id("text")); /// .with_id("text"));
@ -360,10 +414,10 @@ impl Cursive {
/// ///
/// # Examples /// # Examples
/// ///
/// ```rust,no_run /// ```rust
/// # use cursive::Cursive; /// # use cursive::Cursive;
/// # use cursive::views::{TextView, ViewRef}; /// # use cursive::views::{TextView, ViewRef};
/// # let mut siv = Cursive::new(); /// # let mut siv = Cursive::dummy();
/// use cursive::traits::Identifiable; /// use cursive::traits::Identifiable;
/// ///
/// siv.add_layer(TextView::new("foo").with_id("id")); /// siv.add_layer(TextView::new("foo").with_id("id"));
@ -400,11 +454,11 @@ impl Cursive {
/// ///
/// # Examples /// # Examples
/// ///
/// ```rust,no_run /// ```rust
/// # extern crate cursive; /// # extern crate cursive;
/// # use cursive::*; /// # use cursive::*;
/// # fn main() { /// # fn main() {
/// let mut siv = Cursive::new(); /// let mut siv = Cursive::dummy();
/// ///
/// siv.add_global_callback('q', |s| s.quit()); /// siv.add_global_callback('q', |s| s.quit());
/// # } /// # }
@ -423,11 +477,11 @@ impl Cursive {
/// ///
/// # Examples /// # Examples
/// ///
/// ```rust,no_run /// ```rust
/// # extern crate cursive; /// # extern crate cursive;
/// # use cursive::*; /// # use cursive::*;
/// # fn main() { /// # fn main() {
/// let mut siv = Cursive::new(); /// let mut siv = Cursive::dummy();
/// ///
/// siv.add_global_callback('q', |s| s.quit()); /// siv.add_global_callback('q', |s| s.quit());
/// siv.clear_global_callbacks('q'); /// siv.clear_global_callbacks('q');
@ -445,11 +499,11 @@ impl Cursive {
/// ///
/// # Examples /// # Examples
/// ///
/// ```rust,no_run /// ```rust
/// # extern crate cursive; /// # extern crate cursive;
/// # use cursive::*; /// # use cursive::*;
/// # fn main() { /// # fn main() {
/// let mut siv = Cursive::new(); /// let mut siv = Cursive::dummy();
/// ///
/// siv.add_layer(views::TextView::new("Hello world!")); /// siv.add_layer(views::TextView::new("Hello world!"));
/// # } /// # }

View File

@ -32,14 +32,14 @@
//! //!
//! ## Examples //! ## Examples
//! //!
//! ```no_run //! ```rust
//! extern crate cursive; //! extern crate cursive;
//! //!
//! use cursive::Cursive; //! use cursive::Cursive;
//! use cursive::views::TextView; //! use cursive::views::TextView;
//! //!
//! fn main() { //! fn main() {
//! let mut siv = Cursive::new(); //! let mut siv = Cursive::dummy();
//! //!
//! siv.add_layer(TextView::new("Hello World!\nPress q to quit.")); //! siv.add_layer(TextView::new("Hello World!\nPress q to quit."));
//! //!

View File

@ -117,11 +117,11 @@ impl<'a> Printer<'a> {
/// ///
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```rust
/// # use cursive::Printer; /// # use cursive::Printer;
/// # use cursive::theme; /// # use cursive::theme;
/// # use cursive::backend::{self, Backend}; /// # use cursive::backend;
/// # let b: Box<Backend> = backend::Concrete::init(); /// # let b = backend::dummy::Backend::init();
/// # let t = theme::load_default(); /// # let t = theme::load_default();
/// # let printer = Printer::new((6,4), &t, &b); /// # let printer = Printer::new((6,4), &t, &b);
/// printer.with_color(theme::ColorStyle::highlight(), |printer| { /// printer.with_color(theme::ColorStyle::highlight(), |printer| {
@ -195,11 +195,11 @@ impl<'a> Printer<'a> {
/// ///
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```rust
/// # use cursive::Printer; /// # use cursive::Printer;
/// # use cursive::theme; /// # use cursive::theme;
/// # use cursive::backend::{self, Backend}; /// # use cursive::backend;
/// # let b: Box<Backend> = backend::Concrete::init(); /// # let b = backend::dummy::Backend::init();
/// # let t = theme::load_default(); /// # let t = theme::load_default();
/// # let printer = Printer::new((6,4), &t, &b); /// # let printer = Printer::new((6,4), &t, &b);
/// printer.print_box((0,0), (6,4), false); /// printer.print_box((0,0), (6,4), false);

View File

@ -13,13 +13,13 @@ pub trait Identifiable: View + Sized {
/// ///
/// # Examples /// # Examples
/// ///
/// ```rust,no_run /// ```rust
/// # use cursive::Cursive; /// # use cursive::Cursive;
/// # use cursive::views::TextView; /// # use cursive::views::TextView;
/// # use cursive::view::Boxable; /// # use cursive::view::Boxable;
/// use cursive::view::Identifiable; /// use cursive::view::Identifiable;
/// ///
/// let mut siv = Cursive::new(); /// let mut siv = Cursive::dummy();
/// siv.add_layer( /// siv.add_layer(
/// TextView::new("foo") /// TextView::new("foo")
/// .with_id("text") /// .with_id("text")

View File

@ -226,13 +226,13 @@ impl ScrollBase {
/// ///
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```rust
/// # use cursive::view::ScrollBase; /// # use cursive::view::ScrollBase;
/// # use cursive::Printer; /// # use cursive::Printer;
/// # use cursive::theme; /// # use cursive::theme;
/// # use cursive::backend::{self, Backend}; /// # use cursive::backend;
/// # let scrollbase = ScrollBase::new(); /// # let scrollbase = ScrollBase::new();
/// # let b: Box<Backend> = backend::Concrete::init(); /// # let b = backend::dummy::Backend::init();
/// # let t = theme::load_default(); /// # let t = theme::load_default();
/// # let printer = Printer::new((5,1), &t, &b); /// # let printer = Printer::new((5,1), &t, &b);
/// # let printer = &printer; /// # let printer = &printer;

View File

@ -141,7 +141,7 @@ impl<T: ViewWrapper> View for T {
/// ///
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```rust
/// # #[macro_use] extern crate cursive; /// # #[macro_use] extern crate cursive;
/// # use cursive::view::{View,ViewWrapper}; /// # use cursive::view::{View,ViewWrapper};
/// struct FooView<T: View> { /// struct FooView<T: View> {
@ -186,7 +186,7 @@ macro_rules! wrap_impl {
/// ///
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```rust
/// # #[macro_use] extern crate cursive; /// # #[macro_use] extern crate cursive;
/// # use cursive::view::{View,ViewWrapper}; /// # use cursive::view::{View,ViewWrapper};
/// struct FooView<T: View> { /// struct FooView<T: View> {

View File

@ -29,13 +29,13 @@ pub type OnSubmit = Fn(&mut Cursive, &str);
/// ///
/// [1]: https://github.com/gyscos/Cursive/blob/master/examples/edit.rs /// [1]: https://github.com/gyscos/Cursive/blob/master/examples/edit.rs
/// ///
/// ```no_run /// ```rust
/// # extern crate cursive; /// # extern crate cursive;
/// # use cursive::Cursive; /// # use cursive::Cursive;
/// # use cursive::traits::*; /// # use cursive::traits::*;
/// # use cursive::views::{Dialog, EditView, TextView}; /// # use cursive::views::{Dialog, EditView, TextView};
/// # fn main() { /// # fn main() {
/// let mut siv = Cursive::new(); /// let mut siv = Cursive::dummy();
/// ///
/// // Create a dialog with an edit text and a button. /// // Create a dialog with an edit text and a button.
/// // The user can either hit the <Ok> button, /// // The user can either hit the <Ok> button,

View File

@ -21,7 +21,7 @@ use views::MenuPopup;
/// ///
/// # Examples /// # Examples
/// ///
/// ```no_run /// ```rust
/// # extern crate cursive; /// # extern crate cursive;
/// # use cursive::Cursive; /// # use cursive::Cursive;
/// # use cursive::views::{SelectView, Dialog, TextView}; /// # use cursive::views::{SelectView, Dialog, TextView};
@ -39,7 +39,7 @@ use views::MenuPopup;
/// .button("Quit", |s| s.quit())); /// .button("Quit", |s| s.quit()));
/// }); /// });
/// ///
/// let mut siv = Cursive::new(); /// let mut siv = Cursive::dummy();
/// siv.add_layer(Dialog::around(time_select) /// siv.add_layer(Dialog::around(time_select)
/// .title("How long is your wait?")); /// .title("How long is your wait?"));
/// # } /// # }

View File

@ -155,10 +155,10 @@ impl TextContentInner {
/// ///
/// # Examples /// # Examples
/// ///
/// ```rust,no_run /// ```rust
/// # use cursive::Cursive; /// # use cursive::Cursive;
/// # use cursive::views::TextView; /// # use cursive::views::TextView;
/// let mut siv = Cursive::new(); /// let mut siv = Cursive::dummy();
/// ///
/// siv.add_layer(TextView::new("Hello world!")); /// siv.add_layer(TextView::new("Hello world!"));
/// ``` /// ```