diff --git a/examples/theme_manual.rs b/examples/theme_manual.rs index b7b5e57..6229994 100644 --- a/examples/theme_manual.rs +++ b/examples/theme_manual.rs @@ -1,26 +1,33 @@ extern crate cursive; use cursive::Cursive; -use cursive::views::Dialog; -use cursive::theme::BorderStyle; +use cursive::theme::{ColorStyle, BaseColor, Color, BorderStyle}; +use cursive::views::{EditView, LinearLayout, Dialog, TextView}; fn main() { let mut siv = Cursive::new(); - siv.add_layer(Dialog::text("This is a dynamic theme example!") - .button("Change", |s| { - let mut theme = s.current_theme().clone(); + let layout = LinearLayout::vertical() + .child(TextView::new("This is a dynamic theme example!")) + .child(EditView::new().content("Woo! colors!").style(ColorStyle::Custom { + front: Color::Rgb(200, 150, 150), + back: Color::Dark(BaseColor::Blue), + })); - theme.shadow = !theme.shadow; - theme.borders = match theme.borders { - Some(BorderStyle::Simple) => Some(BorderStyle::Outset), - Some(BorderStyle::Outset) => None, - None => Some(BorderStyle::Simple), - }; + siv.add_layer(Dialog::around(layout) + .button("Change", |s| { + let mut theme = s.current_theme().clone(); - s.set_theme(theme); - }) - .button("Quit", Cursive::quit)); + theme.shadow = !theme.shadow; + theme.borders = match theme.borders { + Some(BorderStyle::Simple) => Some(BorderStyle::Outset), + Some(BorderStyle::Outset) => None, + None => Some(BorderStyle::Simple), + }; + + s.set_theme(theme); + }) + .button("Quit", Cursive::quit)); siv.run(); } diff --git a/src/backend/curses/mod.rs b/src/backend/curses/mod.rs index e0ec9fc..fb23906 100644 --- a/src/backend/curses/mod.rs +++ b/src/backend/curses/mod.rs @@ -50,7 +50,6 @@ fn color_id(style: ColorStyle) -> i16 { ColorStyle::TitleSecondary => 7, ColorStyle::Highlight => 8, ColorStyle::HighlightInactive => 9, - ColorStyle::Custom { front, back } => 10, - + ColorStyle::Custom { .. } => 10, } } diff --git a/src/backend/curses/n.rs b/src/backend/curses/n.rs index 0b04e47..a385836 100644 --- a/src/backend/curses/n.rs +++ b/src/backend/curses/n.rs @@ -4,10 +4,13 @@ extern crate ncurses; use self::super::{color_id, find_closest}; use backend; use event::{Event, Key}; +use std::cell::Cell; use theme::{Color, ColorStyle, Effect}; use utf8; -pub struct Concrete; +pub struct Concrete { + current_style: Cell, +} impl backend::Backend for Concrete { fn init() -> Self { @@ -25,7 +28,7 @@ impl backend::Backend for Concrete { ncurses::wbkgd(ncurses::stdscr(), ncurses::COLOR_PAIR(color_id(ColorStyle::Background))); - Concrete + Concrete { current_style: Cell::new(ColorStyle::Background) } } fn screen_size(&self) -> (usize, usize) { @@ -46,7 +49,6 @@ impl backend::Backend for Concrete { fn init_color_style(&mut self, style: ColorStyle, foreground: &Color, background: &Color) { - // TODO: build the color on the spot ncurses::init_pair(color_id(style), find_closest(foreground) as i16, @@ -54,15 +56,13 @@ impl backend::Backend for Concrete { } fn with_color(&self, color: ColorStyle, f: F) { - let mut current_style: ncurses::attr_t = 0; - let mut current_color: i16 = 0; - ncurses::attr_get(&mut current_style, &mut current_color); + let current = self.current_style.get(); - let style = ncurses::COLOR_PAIR(color_id(color)); - ncurses::attron(style); + self.current_style.set(color); + set_colorstyle(color); f(); - // ncurses::attroff(style); - ncurses::attron(current_style); + set_colorstyle(current); + self.current_style.set(current); } fn with_effect(&self, effect: Effect, f: F) { @@ -109,6 +109,21 @@ impl backend::Backend for Concrete { } } +fn set_colorstyle(style: ColorStyle) { + if let ColorStyle::Custom { + ref front, + ref back, + } = style { + + println_stderr!("Redifining..."); + ncurses::init_pair(color_id(style), + find_closest(front) as i16, + find_closest(back) as i16); + } + let style = ncurses::COLOR_PAIR(color_id(style)); + ncurses::attron(style); +} + /// Returns the Key enum corresponding to the given ncurses event. fn parse_ncurses_char(ch: i32) -> Event { match ch { diff --git a/src/backend/termion.rs b/src/backend/termion.rs index 8776fe3..f909b77 100644 --- a/src/backend/termion.rs +++ b/src/backend/termion.rs @@ -13,7 +13,7 @@ use backend; use chan; use event::{Event, Key}; use std::cell::Cell; -use std::collections::BTreeMap; +use std::collections::HashMap; use std::fmt; use std::io::Write; use std::thread; @@ -23,7 +23,7 @@ use theme; pub struct Concrete { terminal: AlternateScreen>, current_style: Cell, - colors: BTreeMap, Box)>, + colors: HashMap, Box)>, input: chan::Receiver, resize: chan::Receiver, @@ -35,20 +35,6 @@ trait Effectable { fn off(&self); } -struct ColorRef<'a>(&'a tcolor::Color); - -impl<'a> tcolor::Color for ColorRef<'a> { - #[inline] - fn write_fg(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.write_fg(f) - } - - #[inline] - fn write_bg(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.0.write_bg(f) - } -} - impl Effectable for theme::Effect { fn on(&self) { match *self { @@ -66,13 +52,20 @@ impl Effectable for theme::Effect { } fn apply_colors(fg: &tcolor::Color, bg: &tcolor::Color) { - print!("{}{}", tcolor::Fg(ColorRef(fg)), tcolor::Bg(ColorRef(bg))); + print!("{}{}", tcolor::Fg(fg), tcolor::Bg(bg)); } impl Concrete { fn apply_colorstyle(&self, color_style: theme::ColorStyle) { - let (ref fg, ref bg) = self.colors[&color_style.id()]; - apply_colors(&**fg, &**bg); + if let theme::ColorStyle::Custom { front, back } = color_style { + let fg = colour_to_termion_colour(&front); + let bg = colour_to_termion_colour(&back); + apply_colors(&*fg, &*bg); + } else { + let (ref fg, ref bg) = self.colors[&color_style]; + apply_colors(&**fg, &**bg); + } + } } @@ -82,7 +75,9 @@ impl backend::Backend for Concrete { let resize = chan_signal::notify(&[chan_signal::Signal::WINCH]); - let terminal = AlternateScreen::from(::std::io::stdout().into_raw_mode().unwrap()); + let terminal = AlternateScreen::from(::std::io::stdout() + .into_raw_mode() + .unwrap()); let (sender, receiver) = chan::async(); thread::spawn(move || for key in ::std::io::stdin().events() { @@ -94,7 +89,7 @@ impl backend::Backend for Concrete { let backend = Concrete { terminal: terminal, current_style: Cell::new(theme::ColorStyle::Background), - colors: BTreeMap::new(), + colors: HashMap::new(), input: receiver, resize: resize, timeout: None, @@ -114,9 +109,10 @@ impl backend::Backend for Concrete { fn init_color_style(&mut self, style: theme::ColorStyle, foreground: &theme::Color, background: &theme::Color) { // Step 1: convert foreground and background into proper termion Color - self.colors.insert(style.id(), - (colour_to_termion_colour(foreground), - colour_to_termion_colour(background))); + self.colors + .insert(style, + (colour_to_termion_colour(foreground), + colour_to_termion_colour(background))); } fn with_color(&self, color: theme::ColorStyle, f: F) { diff --git a/src/theme.rs b/src/theme.rs index 803bad6..73a73db 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -129,7 +129,7 @@ pub enum Effect { /// No effect Simple, /// Reverses foreground and background colors - Reverse, + Reverse, // TODO: bold, italic, underline } @@ -138,7 +138,7 @@ pub enum Effect { /// Represents a color pair role to use when printing something. /// /// The current theme will assign each role a foreground and background color. -#[derive(Clone,Copy)] +#[derive(Clone,Copy,Debug,PartialEq,Eq,Hash)] pub enum ColorStyle { /// Application background, where no view is present. Background, @@ -342,7 +342,7 @@ fn load_color(target: &mut Color, value: Option<&toml::Value>) -> bool { } /// One of the 8 base colors. -#[derive(Clone,Copy,Debug)] +#[derive(Clone,Copy,Debug,PartialEq,Eq,Hash)] pub enum BaseColor { /// Black color /// @@ -379,7 +379,7 @@ pub enum BaseColor { } /// Represents a color used by the theme. -#[derive(Clone,Copy,Debug)] +#[derive(Clone,Copy,Debug,PartialEq,Eq,Hash)] pub enum Color { /// One of the 8 base colors. Dark(BaseColor),