Set up Custom color in termion and ncurses backends

This commit is contained in:
Alexandre Bury 2017-06-11 15:01:35 -07:00
parent b799d83077
commit 9e1a83f7cc
5 changed files with 71 additions and 54 deletions

View File

@ -1,13 +1,20 @@
extern crate cursive; extern crate cursive;
use cursive::Cursive; use cursive::Cursive;
use cursive::views::Dialog; use cursive::theme::{ColorStyle, BaseColor, Color, BorderStyle};
use cursive::theme::BorderStyle; use cursive::views::{EditView, LinearLayout, Dialog, TextView};
fn main() { fn main() {
let mut siv = Cursive::new(); let mut siv = Cursive::new();
siv.add_layer(Dialog::text("This is a dynamic theme example!") 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),
}));
siv.add_layer(Dialog::around(layout)
.button("Change", |s| { .button("Change", |s| {
let mut theme = s.current_theme().clone(); let mut theme = s.current_theme().clone();

View File

@ -50,7 +50,6 @@ fn color_id(style: ColorStyle) -> i16 {
ColorStyle::TitleSecondary => 7, ColorStyle::TitleSecondary => 7,
ColorStyle::Highlight => 8, ColorStyle::Highlight => 8,
ColorStyle::HighlightInactive => 9, ColorStyle::HighlightInactive => 9,
ColorStyle::Custom { front, back } => 10, ColorStyle::Custom { .. } => 10,
} }
} }

View File

@ -4,10 +4,13 @@ extern crate ncurses;
use self::super::{color_id, find_closest}; use self::super::{color_id, find_closest};
use backend; use backend;
use event::{Event, Key}; use event::{Event, Key};
use std::cell::Cell;
use theme::{Color, ColorStyle, Effect}; use theme::{Color, ColorStyle, Effect};
use utf8; use utf8;
pub struct Concrete; pub struct Concrete {
current_style: Cell<ColorStyle>,
}
impl backend::Backend for Concrete { impl backend::Backend for Concrete {
fn init() -> Self { fn init() -> Self {
@ -25,7 +28,7 @@ impl backend::Backend for Concrete {
ncurses::wbkgd(ncurses::stdscr(), ncurses::wbkgd(ncurses::stdscr(),
ncurses::COLOR_PAIR(color_id(ColorStyle::Background))); ncurses::COLOR_PAIR(color_id(ColorStyle::Background)));
Concrete Concrete { current_style: Cell::new(ColorStyle::Background) }
} }
fn screen_size(&self) -> (usize, usize) { 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, fn init_color_style(&mut self, style: ColorStyle, foreground: &Color,
background: &Color) { background: &Color) {
// TODO: build the color on the spot
ncurses::init_pair(color_id(style), ncurses::init_pair(color_id(style),
find_closest(foreground) as i16, find_closest(foreground) as i16,
@ -54,15 +56,13 @@ impl backend::Backend for Concrete {
} }
fn with_color<F: FnOnce()>(&self, color: ColorStyle, f: F) { fn with_color<F: FnOnce()>(&self, color: ColorStyle, f: F) {
let mut current_style: ncurses::attr_t = 0; let current = self.current_style.get();
let mut current_color: i16 = 0;
ncurses::attr_get(&mut current_style, &mut current_color);
let style = ncurses::COLOR_PAIR(color_id(color)); self.current_style.set(color);
ncurses::attron(style); set_colorstyle(color);
f(); f();
// ncurses::attroff(style); set_colorstyle(current);
ncurses::attron(current_style); self.current_style.set(current);
} }
fn with_effect<F: FnOnce()>(&self, effect: Effect, f: F) { fn with_effect<F: FnOnce()>(&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. /// Returns the Key enum corresponding to the given ncurses event.
fn parse_ncurses_char(ch: i32) -> Event { fn parse_ncurses_char(ch: i32) -> Event {
match ch { match ch {

View File

@ -13,7 +13,7 @@ use backend;
use chan; use chan;
use event::{Event, Key}; use event::{Event, Key};
use std::cell::Cell; use std::cell::Cell;
use std::collections::BTreeMap; use std::collections::HashMap;
use std::fmt; use std::fmt;
use std::io::Write; use std::io::Write;
use std::thread; use std::thread;
@ -23,7 +23,7 @@ use theme;
pub struct Concrete { pub struct Concrete {
terminal: AlternateScreen<termion::raw::RawTerminal<::std::io::Stdout>>, terminal: AlternateScreen<termion::raw::RawTerminal<::std::io::Stdout>>,
current_style: Cell<theme::ColorStyle>, current_style: Cell<theme::ColorStyle>,
colors: BTreeMap<i16, (Box<tcolor::Color>, Box<tcolor::Color>)>, colors: HashMap<theme::ColorStyle, (Box<tcolor::Color>, Box<tcolor::Color>)>,
input: chan::Receiver<Event>, input: chan::Receiver<Event>,
resize: chan::Receiver<chan_signal::Signal>, resize: chan::Receiver<chan_signal::Signal>,
@ -35,20 +35,6 @@ trait Effectable {
fn off(&self); 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 { impl Effectable for theme::Effect {
fn on(&self) { fn on(&self) {
match *self { match *self {
@ -66,14 +52,21 @@ impl Effectable for theme::Effect {
} }
fn apply_colors(fg: &tcolor::Color, bg: &tcolor::Color) { 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 { impl Concrete {
fn apply_colorstyle(&self, color_style: theme::ColorStyle) { fn apply_colorstyle(&self, color_style: theme::ColorStyle) {
let (ref fg, ref bg) = self.colors[&color_style.id()]; 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); apply_colors(&**fg, &**bg);
} }
}
} }
impl backend::Backend for Concrete { impl backend::Backend for Concrete {
@ -82,7 +75,9 @@ impl backend::Backend for Concrete {
let resize = chan_signal::notify(&[chan_signal::Signal::WINCH]); 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(); let (sender, receiver) = chan::async();
thread::spawn(move || for key in ::std::io::stdin().events() { thread::spawn(move || for key in ::std::io::stdin().events() {
@ -94,7 +89,7 @@ impl backend::Backend for Concrete {
let backend = Concrete { let backend = Concrete {
terminal: terminal, terminal: terminal,
current_style: Cell::new(theme::ColorStyle::Background), current_style: Cell::new(theme::ColorStyle::Background),
colors: BTreeMap::new(), colors: HashMap::new(),
input: receiver, input: receiver,
resize: resize, resize: resize,
timeout: None, timeout: None,
@ -114,7 +109,8 @@ impl backend::Backend for Concrete {
fn init_color_style(&mut self, style: theme::ColorStyle, fn init_color_style(&mut self, style: theme::ColorStyle,
foreground: &theme::Color, background: &theme::Color) { foreground: &theme::Color, background: &theme::Color) {
// Step 1: convert foreground and background into proper termion Color // Step 1: convert foreground and background into proper termion Color
self.colors.insert(style.id(), self.colors
.insert(style,
(colour_to_termion_colour(foreground), (colour_to_termion_colour(foreground),
colour_to_termion_colour(background))); colour_to_termion_colour(background)));
} }

View File

@ -138,7 +138,7 @@ pub enum Effect {
/// Represents a color pair role to use when printing something. /// Represents a color pair role to use when printing something.
/// ///
/// The current theme will assign each role a foreground and background color. /// 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 { pub enum ColorStyle {
/// Application background, where no view is present. /// Application background, where no view is present.
Background, Background,
@ -342,7 +342,7 @@ fn load_color(target: &mut Color, value: Option<&toml::Value>) -> bool {
} }
/// One of the 8 base colors. /// One of the 8 base colors.
#[derive(Clone,Copy,Debug)] #[derive(Clone,Copy,Debug,PartialEq,Eq,Hash)]
pub enum BaseColor { pub enum BaseColor {
/// Black color /// Black color
/// ///
@ -379,7 +379,7 @@ pub enum BaseColor {
} }
/// Represents a color used by the theme. /// Represents a color used by the theme.
#[derive(Clone,Copy,Debug)] #[derive(Clone,Copy,Debug,PartialEq,Eq,Hash)]
pub enum Color { pub enum Color {
/// One of the 8 base colors. /// One of the 8 base colors.
Dark(BaseColor), Dark(BaseColor),