Making backend::Backend into a std::Boxable trait (#229)

* Making Backend into a Boxable Trait

* Fixed up some typos in the previous and modified some of the docs so they still compile.

* Minor Changes requested by @gyscos

* Whoops
This commit is contained in:
SEGFAULT 2018-04-02 00:35:37 +02:00 committed by Alexandre Bury
parent 8c64ea0101
commit 76d340f11d
8 changed files with 105 additions and 60 deletions

View File

@ -145,7 +145,7 @@ impl Concrete {
}
impl backend::Backend for Concrete {
fn init() -> Self {
fn init() -> Box<Self> {
terminal::open("Cursive", 80, 24);
terminal::set(terminal::config::Window::empty().resizeable(true));
terminal::set(vec![
@ -159,37 +159,59 @@ impl backend::Backend for Concrete {
},
]);
Concrete {
let c = Concrete {
mouse_position: Vec2::zero(),
buttons_pressed: HashSet::new(),
}
};
Box::new(c)
}
fn finish(&mut self) {
terminal::close();
}
fn with_color<F: FnOnce()>(&self, color: ColorPair, f: F) {
fn set_color(&self, color: ColorPair) -> ColorPair {
let current = ColorPair {
front: blt_colour_to_colour(state::foreground()),
back: blt_colour_to_colour(state::background())
};
let fg = colour_to_blt_colour(color.front, ColorRole::Foreground);
let bg = colour_to_blt_colour(color.back, ColorRole::Background);
terminal::with_colors(fg, bg, f);
terminal::set_colors(fg, bg);
current
}
fn with_effect<F: FnOnce()>(&self, effect: Effect, f: F) {
fn set_effect(&self, effect: Effect) {
match effect {
// TODO: does BLT support bold/italic/underline?
Effect::Bold
| Effect::Italic
| Effect::Underline
| Effect::Simple => f(),
| Effect::Simple => {},
// TODO: how to do this correctly?`
// BLT itself doesn't do this kind of thing,
// we'd need the colours in our position,
// but `f()` can do whatever
Effect::Reverse => terminal::with_colors(
BltColor::from_rgb(0, 0, 0),
BltColor::from_rgb(255, 255, 255),
f,
Effect::Reverse => terminal::set_colors(
state::background(), state::foreground()
),
}
}
fn unset_effect(&self, effect: Effect) {
match effect {
// TODO: does BLT support bold/italic/underline?
Effect::Bold
| Effect::Italic
| Effect::Underline
| Effect::Simple => {},
// The process of reversing is the same as unreversing
Effect::Reverse => terminal::set_colors(
state::background(), state::foreground()
),
}
}
@ -282,6 +304,10 @@ impl backend::Backend for Concrete {
}
}
fn blt_colour_to_colour(c: BltColor) -> Color {
Color::Rgb(c.red, c.green, c.blue)
}
fn colour_to_blt_colour(clr: Color, role: ColorRole) -> BltColor {
let (r, g, b) = match clr {
Color::TerminalDefault => {

View File

@ -150,7 +150,7 @@ impl Concrete {
}
impl backend::Backend for Concrete {
fn init() -> Self {
fn init() -> Box<Self> {
// Change the locale.
// For some reasons it's mandatory to get some UTF-8 support.
ncurses::setlocale(ncurses::LcCategory::all, "");
@ -186,7 +186,7 @@ impl backend::Backend for Concrete {
print!("\x1B[?1002h");
stdout().flush().expect("could not flush stdout");
Concrete {
let c = Concrete {
current_style: Cell::new(ColorPair::from_256colors(0, 0)),
pairs: RefCell::new(HashMap::new()),
@ -194,7 +194,9 @@ impl backend::Backend for Concrete {
event_queue: Vec::new(),
key_codes: initialize_keymap(),
}
};
Box::new(c)
}
fn screen_size(&self) -> (usize, usize) {
@ -214,21 +216,16 @@ impl backend::Backend for Concrete {
ncurses::endwin();
}
fn with_color<F: FnOnce()>(&self, colors: ColorPair, f: F) {
fn set_color(&self, colors: ColorPair) -> ColorPair {
// eprintln!("Color used: {:?}", colors);
let current = self.current_style.get();
if current != colors {
self.set_colors(colors);
}
f();
if current != colors {
self.set_colors(current);
}
return current;
}
fn with_effect<F: FnOnce()>(&self, effect: Effect, f: F) {
fn set_effect(&self, effect: Effect) {
let style = match effect {
Effect::Reverse => ncurses::A_REVERSE(),
Effect::Simple => ncurses::A_NORMAL(),
@ -237,7 +234,16 @@ impl backend::Backend for Concrete {
Effect::Underline => ncurses::A_UNDERLINE(),
};
ncurses::attron(style);
f();
}
fn unset_effect(&self, effect: Effect) {
let style = match effect {
Effect::Reverse => ncurses::A_REVERSE(),
Effect::Simple => ncurses::A_NORMAL(),
Effect::Bold => ncurses::A_BOLD(),
Effect::Italic => ncurses::A_ITALIC(),
Effect::Underline => ncurses::A_UNDERLINE(),
};
ncurses::attroff(style);
}

View File

@ -133,7 +133,7 @@ impl Concrete {
}
impl backend::Backend for Concrete {
fn init() -> Self {
fn init() -> Box<Self> {
::std::env::set_var("ESCDELAY", "25");
let window = pancurses::initscr();
@ -155,14 +155,16 @@ impl backend::Backend for Concrete {
print!("\x1B[?1002h");
stdout().flush().expect("could not flush stdout");
Concrete {
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) {
@ -180,21 +182,17 @@ impl backend::Backend for Concrete {
pancurses::endwin();
}
fn with_color<F: FnOnce()>(&self, colors: ColorPair, f: F) {
fn set_color(&self, colors: ColorPair) -> ColorPair {
let current = self.current_style.get();
if current != colors {
self.set_colors(colors);
}
f();
if current != colors {
self.set_colors(current);
}
current
}
fn with_effect<F: FnOnce()>(&self, effect: Effect, f: F) {
fn set_effect(&self, effect: Effect) {
let style = match effect {
Effect::Simple => pancurses::Attribute::Normal,
Effect::Reverse => pancurses::Attribute::Reverse,
@ -203,7 +201,16 @@ impl backend::Backend for Concrete {
Effect::Underline => pancurses::Attribute::Underline,
};
self.window.attron(style);
f();
}
fn unset_effect(&self, effect: Effect) {
let style = match effect {
Effect::Simple => pancurses::Attribute::Normal,
Effect::Reverse => pancurses::Attribute::Reverse,
Effect::Bold => pancurses::Attribute::Bold,
Effect::Italic => pancurses::Attribute::Italic,
Effect::Underline => pancurses::Attribute::Underline,
};
self.window.attroff(style);
}

View File

@ -16,7 +16,7 @@ pub use self::curses::*;
pub use self::termion::*;
pub trait Backend {
fn init() -> Self;
fn init() -> Box<Self> where Self: Sized;
// TODO: take `self` by value?
// Or implement Drop?
fn finish(&mut self);
@ -34,7 +34,11 @@ pub trait Backend {
fn clear(&self, color: theme::Color);
fn set_refresh_rate(&mut self, fps: u32);
// TODO: unify those into a single method?
fn with_color<F: FnOnce()>(&self, colors: theme::ColorPair, f: F);
fn with_effect<F: FnOnce()>(&self, effect: theme::Effect, f: F);
// 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;
fn set_effect(&self, effect: theme::Effect);
fn unset_effect(&self, effect: theme::Effect);
}

View File

@ -137,7 +137,7 @@ impl Concrete {
}
impl backend::Backend for Concrete {
fn init() -> Self {
fn init() -> Box<Self> {
print!("{}", termion::cursor::Hide);
let resize = chan_signal::notify(&[chan_signal::Signal::WINCH]);
@ -157,14 +157,16 @@ impl backend::Backend for Concrete {
}
});
Concrete {
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) {
@ -177,7 +179,7 @@ impl backend::Backend for Concrete {
);
}
fn with_color<F: FnOnce()>(&self, color: theme::ColorPair, f: F) {
fn set_color(&self, color: theme::ColorPair) -> theme::ColorPair {
let current_style = self.current_style.get();
if current_style != color {
@ -185,17 +187,14 @@ impl backend::Backend for Concrete {
self.current_style.set(color);
}
f();
if current_style != color {
self.current_style.set(current_style);
self.apply_colors(current_style);
}
return current_style;
}
fn with_effect<F: FnOnce()>(&self, effect: theme::Effect, f: F) {
fn set_effect(&self, effect: theme::Effect) {
effect.on();
f();
}
fn unset_effect(&self, effect: theme::Effect) {
effect.off();
}

View File

@ -54,7 +54,7 @@ pub struct Cursive {
running: bool,
backend: backend::Concrete,
backend: Box<backend::Backend>,
cb_source: mpsc::Receiver<Box<CbFunc>>,
cb_sink: mpsc::Sender<Box<CbFunc>>,

View File

@ -1,6 +1,6 @@
//! Makes drawing on ncurses windows easier.
use backend::{self, Backend};
use backend::Backend;
use enumset::EnumSet;
use std::cell::Cell;
use std::cmp::min;
@ -24,7 +24,7 @@ pub struct Printer<'a> {
/// `true` if nothing has been drawn yet.
new: Rc<Cell<bool>>,
/// Backend used to actually draw things
backend: &'a backend::Concrete,
backend: &'a Box<Backend>,
}
impl<'a> Printer<'a> {
@ -33,7 +33,7 @@ impl<'a> Printer<'a> {
/// But nobody needs to know that.
#[doc(hidden)]
pub fn new<T: Into<Vec2>>(
size: T, theme: &'a Theme, backend: &'a backend::Concrete
size: T, theme: &'a Theme, backend: &'a Box<Backend>
) -> Self {
Printer {
offset: Vec2::zero(),
@ -121,7 +121,7 @@ impl<'a> Printer<'a> {
/// # use cursive::Printer;
/// # use cursive::theme;
/// # use cursive::backend::{self, Backend};
/// # let b = backend::Concrete::init();
/// # let b: Box<Backend> = backend::Concrete::init();
/// # let t = theme::load_default();
/// # let printer = Printer::new((6,4), &t, &b);
/// printer.with_color(theme::ColorStyle::highlight(), |printer| {
@ -132,8 +132,9 @@ impl<'a> Printer<'a> {
where
F: FnOnce(&Printer),
{
self.backend
.with_color(c.resolve(&self.theme.palette), || f(self));
let old = self.backend.set_color(c.resolve(&self.theme.palette));
f(self);
self.backend.set_color(old);
}
/// Call the given closure with a styled printer,
@ -165,7 +166,9 @@ impl<'a> Printer<'a> {
where
F: FnOnce(&Printer),
{
self.backend.with_effect(effect, || f(self));
self.backend.set_effect(effect);
f(self);
self.backend.unset_effect(effect);
}
/// Call the given closure with a modified printer
@ -196,7 +199,7 @@ impl<'a> Printer<'a> {
/// # use cursive::Printer;
/// # use cursive::theme;
/// # use cursive::backend::{self, Backend};
/// # let b = backend::Concrete::init();
/// # let b: Box<Backend> = backend::Concrete::init();
/// # let t = theme::load_default();
/// # let printer = Printer::new((6,4), &t, &b);
/// printer.print_box((0,0), (6,4), false);

View File

@ -232,7 +232,7 @@ impl ScrollBase {
/// # use cursive::theme;
/// # use cursive::backend::{self, Backend};
/// # let scrollbase = ScrollBase::new();
/// # let b = backend::Concrete::init();
/// # let b: Box<Backend> = backend::Concrete::init();
/// # let t = theme::load_default();
/// # let printer = Printer::new((5,1), &t, &b);
/// # let printer = &printer;