diff --git a/src/backend/blt.rs b/src/backend/blt.rs index f3a47cc..3c28b6c 100644 --- a/src/backend/blt.rs +++ b/src/backend/blt.rs @@ -145,7 +145,7 @@ impl Concrete { } impl backend::Backend for Concrete { - fn init() -> Self { + fn init() -> Box { 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(&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(&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 => { diff --git a/src/backend/curses/n.rs b/src/backend/curses/n.rs index ad88f9e..7624598 100644 --- a/src/backend/curses/n.rs +++ b/src/backend/curses/n.rs @@ -150,7 +150,7 @@ impl Concrete { } impl backend::Backend for Concrete { - fn init() -> Self { + fn init() -> Box { // 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(&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(&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); } diff --git a/src/backend/curses/pan.rs b/src/backend/curses/pan.rs index 48f905d..ba9741e 100644 --- a/src/backend/curses/pan.rs +++ b/src/backend/curses/pan.rs @@ -133,7 +133,7 @@ impl Concrete { } impl backend::Backend for Concrete { - fn init() -> Self { + fn init() -> Box { ::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(&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(&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); } diff --git a/src/backend/mod.rs b/src/backend/mod.rs index f5619f8..4e6cd0f 100644 --- a/src/backend/mod.rs +++ b/src/backend/mod.rs @@ -16,7 +16,7 @@ pub use self::curses::*; pub use self::termion::*; pub trait Backend { - fn init() -> Self; + fn init() -> Box 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(&self, colors: theme::ColorPair, f: F); - fn with_effect(&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); } diff --git a/src/backend/termion.rs b/src/backend/termion.rs index 3eeb3e3..33b3a3b 100644 --- a/src/backend/termion.rs +++ b/src/backend/termion.rs @@ -137,7 +137,7 @@ impl Concrete { } impl backend::Backend for Concrete { - fn init() -> Self { + fn init() -> Box { 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(&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(&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(); } diff --git a/src/cursive.rs b/src/cursive.rs index 2af1d5b..8626f00 100644 --- a/src/cursive.rs +++ b/src/cursive.rs @@ -54,7 +54,7 @@ pub struct Cursive { running: bool, - backend: backend::Concrete, + backend: Box, cb_source: mpsc::Receiver>, cb_sink: mpsc::Sender>, diff --git a/src/printer.rs b/src/printer.rs index f55a4ee..1b49ff4 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -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>, /// Backend used to actually draw things - backend: &'a backend::Concrete, + backend: &'a Box, } impl<'a> Printer<'a> { @@ -33,7 +33,7 @@ impl<'a> Printer<'a> { /// But nobody needs to know that. #[doc(hidden)] pub fn new>( - size: T, theme: &'a Theme, backend: &'a backend::Concrete + size: T, theme: &'a Theme, backend: &'a Box ) -> 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::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::Concrete::init(); /// # let t = theme::load_default(); /// # let printer = Printer::new((6,4), &t, &b); /// printer.print_box((0,0), (6,4), false); diff --git a/src/view/scroll.rs b/src/view/scroll.rs index f9f90b6..0b6dd05 100644 --- a/src/view/scroll.rs +++ b/src/view/scroll.rs @@ -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::Concrete::init(); /// # let t = theme::load_default(); /// # let printer = Printer::new((5,1), &t, &b); /// # let printer = &printer;