diff --git a/src/backend/curses/mod.rs b/src/backend/curses/mod.rs index 683c04c..9d20f27 100644 --- a/src/backend/curses/mod.rs +++ b/src/backend/curses/mod.rs @@ -1,6 +1,6 @@ use event::{Event, Key}; use std::collections::HashMap; -use theme::{BaseColor, Color}; +use theme::{BaseColor, Color, ColorPair}; #[cfg(feature = "ncurses")] mod n; @@ -13,9 +13,7 @@ mod pan; pub use self::pan::*; fn split_i32(code: i32) -> Vec { - (0..4) - .map(|i| ((code >> (8 * i)) & 0xFF) as u8) - .collect() + (0..4).map(|i| ((code >> (8 * i)) & 0xFF) as u8).collect() } fn fill_key_codes(target: &mut HashMap, f: F) @@ -62,7 +60,14 @@ where } } -fn find_closest(color: &Color) -> i16 { +fn find_closest_pair(pair: &ColorPair, max_colors: i16) -> (i16, i16) { + ( + find_closest(&pair.front,max_colors), + find_closest(&pair.back, max_colors), + ) +} + +fn find_closest(color: &Color, max_colors: i16) -> i16 { match *color { Color::TerminalDefault => -1, Color::Dark(BaseColor::Black) => 0, @@ -73,29 +78,45 @@ fn find_closest(color: &Color) -> i16 { Color::Dark(BaseColor::Magenta) => 5, Color::Dark(BaseColor::Cyan) => 6, Color::Dark(BaseColor::White) => 7, - Color::Light(BaseColor::Black) => 8, - Color::Light(BaseColor::Red) => 9, - Color::Light(BaseColor::Green) => 10, - Color::Light(BaseColor::Yellow) => 11, - Color::Light(BaseColor::Blue) => 12, - Color::Light(BaseColor::Magenta) => 13, - Color::Light(BaseColor::Cyan) => 14, - Color::Light(BaseColor::White) => 15, - Color::Rgb(r, g, b) => { + Color::Light(BaseColor::Black) => 8 % max_colors, + Color::Light(BaseColor::Red) => 9 % max_colors, + Color::Light(BaseColor::Green) => 10 % max_colors, + Color::Light(BaseColor::Yellow) => 11 % max_colors, + Color::Light(BaseColor::Blue) => 12 % max_colors, + Color::Light(BaseColor::Magenta) => 13 % max_colors, + Color::Light(BaseColor::Cyan) => 14 % max_colors, + Color::Light(BaseColor::White) => 15 % max_colors, + Color::Rgb(r, g, b) if max_colors >= 256 => { // If r = g = b, it may be a grayscale value! if r == g && g == b && r != 0 && r < 250 { + // Grayscale // (r = g = b) = 8 + 10 * n // (r - 8) / 10 = n // let n = (r - 8) / 10; (232 + n) as i16 } else { + // Generic RGB let r = 6 * u16::from(r) / 256; let g = 6 * u16::from(g) / 256; let b = 6 * u16::from(b) / 256; (16 + 36 * r + 6 * g + b) as i16 } } - Color::RgbLowRes(r, g, b) => i16::from(16 + 36 * r + 6 * g + b), + Color::Rgb(r, g, b) => { + let r = if r > 127 { 1 } else { 0 }; + let g = if g > 127 { 1 } else { 0 }; + let b = if b > 127 { 1 } else { 0 }; + (r + 2 * g + 4 * b) as i16 + } + Color::RgbLowRes(r, g, b) if max_colors >= 256 => { + i16::from(16 + 36 * r + 6 * g + b) + } + Color::RgbLowRes(r, g, b) => { + let r = if r > 2 { 1 } else { 0 }; + let g = if g > 2 { 1 } else { 0 }; + let b = if b > 2 { 1 } else { 0 }; + (r + 2 * g + 4 * b) as i16 + } } } diff --git a/src/backend/curses/n.rs b/src/backend/curses/n.rs index 4ad5b24..8d5bfe5 100644 --- a/src/backend/curses/n.rs +++ b/src/backend/curses/n.rs @@ -1,7 +1,7 @@ extern crate ncurses; use self::ncurses::mmask_t; -use self::super::{find_closest, split_i32}; +use self::super::split_i32; use backend; use event::{Event, Key, MouseButton, MouseEvent}; use std::cell::{Cell, RefCell}; @@ -13,7 +13,9 @@ use vec::Vec2; pub struct Concrete { current_style: Cell, - pairs: RefCell>, + + // Maps (front, back) ncurses colors to ncurses pairs + pairs: RefCell>, key_codes: HashMap, @@ -21,12 +23,17 @@ pub struct Concrete { event_queue: Vec, } +fn find_closest_pair(pair: &ColorPair) -> (i16, i16) { + super::find_closest_pair(pair, ncurses::COLORS() as i16) +} + impl Concrete { /// Save a new color pair. fn insert_color( - &self, pairs: &mut HashMap, pair: ColorPair + &self, pairs: &mut HashMap<(i16, i16), i16>, (front, back): (i16, i16) ) -> i16 { let n = 1 + pairs.len() as i16; + let target = if ncurses::COLOR_PAIRS() > i32::from(n) { // We still have plenty of space for everyone. n @@ -37,12 +44,8 @@ impl Concrete { pairs.retain(|_, &mut v| v != target); target }; - pairs.insert(pair, target); - ncurses::init_pair( - target, - find_closest(&pair.front), - find_closest(&pair.back), - ); + pairs.insert((front, back), target); + ncurses::init_pair(target, front, back); target } @@ -51,11 +54,12 @@ impl Concrete { let mut pairs = self.pairs.borrow_mut(); // Find if we have this color in stock - if pairs.contains_key(&pair) { + let (front, back) = find_closest_pair(&pair); + if pairs.contains_key(&(front, back)) { // We got it! - pairs[&pair] + pairs[&(front, back)] } else { - self.insert_color(&mut *pairs, pair) + self.insert_color(&mut *pairs, (front, back)) } } @@ -184,9 +188,7 @@ impl backend::Backend for Concrete { // (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"); + stdout().flush().expect("could not flush stdout"); Concrete { current_style: Cell::new(ColorPair::from_256colors(0, 0)), @@ -212,9 +214,7 @@ impl backend::Backend for Concrete { fn finish(&mut self) { print!("\x1B[?1002l"); - stdout() - .flush() - .expect("could not flush stdout"); + stdout().flush().expect("could not flush stdout"); ncurses::endwin(); } diff --git a/src/backend/curses/pan.rs b/src/backend/curses/pan.rs index 2f73c17..1938847 100644 --- a/src/backend/curses/pan.rs +++ b/src/backend/curses/pan.rs @@ -1,7 +1,7 @@ extern crate pancurses; use self::pancurses::mmask_t; -use self::super::{find_closest, split_i32}; +use self::super::split_i32; use backend; use event::{Event, Key, MouseButton, MouseEvent}; use std::cell::{Cell, RefCell}; @@ -13,7 +13,7 @@ use vec::Vec2; pub struct Concrete { // Used current_style: Cell, - pairs: RefCell>, + pairs: RefCell>, key_codes: HashMap, @@ -24,10 +24,14 @@ pub struct Concrete { window: pancurses::Window, } +fn find_closest_pair(pair: &ColorPair) -> (i16, i16) { + super::find_closest_pair(pair, pancurses::COLORS() as i16) +} + impl Concrete { /// Save a new color pair. fn insert_color( - &self, pairs: &mut HashMap, pair: ColorPair + &self, pairs: &mut HashMap<(i16, i16), i32>, (front, back): (i16, i16) ) -> i32 { let n = 1 + pairs.len() as i32; @@ -42,18 +46,15 @@ impl Concrete { pairs.retain(|_, &mut v| v != target); target }; - pairs.insert(pair, target); - pancurses::init_pair( - target as i16, - find_closest(&pair.front), - find_closest(&pair.back), - ); + pairs.insert((front, back), target); + pancurses::init_pair(target as i16, front, back); target } /// Checks the pair in the cache, or re-define a color if needed. fn get_or_create(&self, pair: ColorPair) -> i32 { let mut pairs = self.pairs.borrow_mut(); + let pair = find_closest_pair(&pair); // Find if we have this color in stock if pairs.contains_key(&pair) { @@ -153,9 +154,7 @@ impl backend::Backend for Concrete { // (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"); + stdout().flush().expect("could not flush stdout"); Concrete { current_style: Cell::new(ColorPair::from_256colors(0, 0)), @@ -178,9 +177,7 @@ impl backend::Backend for Concrete { fn finish(&mut self) { print!("\x1B[?1002l"); - stdout() - .flush() - .expect("could not flush stdout"); + stdout().flush().expect("could not flush stdout"); pancurses::endwin(); }