mirror of
https://github.com/FliegendeWurst/cursive.git
synced 2024-11-23 17:35:00 +00:00
Ncurses: better color approximation
On terminals with only 8 colors (like with `TERM=screen`)
This commit is contained in:
parent
ff9f669d73
commit
3731b7375d
@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
use event::{Event, Key};
|
use event::{Event, Key};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use theme::{BaseColor, Color};
|
use theme::{BaseColor, Color, ColorPair};
|
||||||
|
|
||||||
#[cfg(feature = "ncurses")]
|
#[cfg(feature = "ncurses")]
|
||||||
pub mod n;
|
pub mod n;
|
||||||
@ -61,7 +61,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 {
|
match *color {
|
||||||
Color::TerminalDefault => -1,
|
Color::TerminalDefault => -1,
|
||||||
Color::Dark(BaseColor::Black) => 0,
|
Color::Dark(BaseColor::Black) => 0,
|
||||||
@ -72,29 +79,45 @@ fn find_closest(color: &Color) -> i16 {
|
|||||||
Color::Dark(BaseColor::Magenta) => 5,
|
Color::Dark(BaseColor::Magenta) => 5,
|
||||||
Color::Dark(BaseColor::Cyan) => 6,
|
Color::Dark(BaseColor::Cyan) => 6,
|
||||||
Color::Dark(BaseColor::White) => 7,
|
Color::Dark(BaseColor::White) => 7,
|
||||||
Color::Light(BaseColor::Black) => 8,
|
Color::Light(BaseColor::Black) => 8 % max_colors,
|
||||||
Color::Light(BaseColor::Red) => 9,
|
Color::Light(BaseColor::Red) => 9 % max_colors,
|
||||||
Color::Light(BaseColor::Green) => 10,
|
Color::Light(BaseColor::Green) => 10 % max_colors,
|
||||||
Color::Light(BaseColor::Yellow) => 11,
|
Color::Light(BaseColor::Yellow) => 11 % max_colors,
|
||||||
Color::Light(BaseColor::Blue) => 12,
|
Color::Light(BaseColor::Blue) => 12 % max_colors,
|
||||||
Color::Light(BaseColor::Magenta) => 13,
|
Color::Light(BaseColor::Magenta) => 13 % max_colors,
|
||||||
Color::Light(BaseColor::Cyan) => 14,
|
Color::Light(BaseColor::Cyan) => 14 % max_colors,
|
||||||
Color::Light(BaseColor::White) => 15,
|
Color::Light(BaseColor::White) => 15 % max_colors,
|
||||||
Color::Rgb(r, g, b) => {
|
Color::Rgb(r, g, b) if max_colors >= 256 => {
|
||||||
// If r = g = b, it may be a grayscale value!
|
// If r = g = b, it may be a grayscale value!
|
||||||
if r == g && g == b && r != 0 && r < 250 {
|
if r == g && g == b && r != 0 && r < 250 {
|
||||||
|
// Grayscale
|
||||||
// (r = g = b) = 8 + 10 * n
|
// (r = g = b) = 8 + 10 * n
|
||||||
// (r - 8) / 10 = n
|
// (r - 8) / 10 = n
|
||||||
//
|
//
|
||||||
let n = (r - 8) / 10;
|
let n = (r - 8) / 10;
|
||||||
(232 + n) as i16
|
(232 + n) as i16
|
||||||
} else {
|
} else {
|
||||||
|
// Generic RGB
|
||||||
let r = 6 * u16::from(r) / 256;
|
let r = 6 * u16::from(r) / 256;
|
||||||
let g = 6 * u16::from(g) / 256;
|
let g = 6 * u16::from(g) / 256;
|
||||||
let b = 6 * u16::from(b) / 256;
|
let b = 6 * u16::from(b) / 256;
|
||||||
(16 + 36 * r + 6 * g + b) as i16
|
(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
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
extern crate ncurses;
|
extern crate ncurses;
|
||||||
|
|
||||||
use self::ncurses::mmask_t;
|
use self::ncurses::mmask_t;
|
||||||
use self::super::{find_closest, split_i32};
|
use self::super::split_i32;
|
||||||
use backend;
|
use backend;
|
||||||
use event::{Event, Key, MouseButton, MouseEvent};
|
use event::{Event, Key, MouseButton, MouseEvent};
|
||||||
use libc;
|
use libc;
|
||||||
@ -17,7 +17,9 @@ use vec::Vec2;
|
|||||||
|
|
||||||
pub struct Backend {
|
pub struct Backend {
|
||||||
current_style: Cell<ColorPair>,
|
current_style: Cell<ColorPair>,
|
||||||
pairs: RefCell<HashMap<ColorPair, i16>>,
|
|
||||||
|
// Maps (front, back) ncurses colors to ncurses pairs
|
||||||
|
pairs: RefCell<HashMap<(i16, i16), i16>>,
|
||||||
|
|
||||||
key_codes: HashMap<i32, Event>,
|
key_codes: HashMap<i32, Event>,
|
||||||
|
|
||||||
@ -25,6 +27,10 @@ pub struct Backend {
|
|||||||
event_queue: Vec<Event>,
|
event_queue: Vec<Event>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_closest_pair(pair: &ColorPair) -> (i16, i16) {
|
||||||
|
super::find_closest_pair(pair, ncurses::COLORS() as i16)
|
||||||
|
}
|
||||||
|
|
||||||
/// Writes some bytes directly to `/dev/tty`
|
/// Writes some bytes directly to `/dev/tty`
|
||||||
///
|
///
|
||||||
/// Since this is not going to be used often, we can afford to re-open the
|
/// Since this is not going to be used often, we can afford to re-open the
|
||||||
@ -89,11 +95,13 @@ impl Backend {
|
|||||||
Box::new(c)
|
Box::new(c)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// Save a new color pair.
|
/// Save a new color pair.
|
||||||
fn insert_color(
|
fn insert_color(
|
||||||
&self, pairs: &mut HashMap<ColorPair, i16>, pair: ColorPair
|
&self, pairs: &mut HashMap<(i16, i16), i16>, (front, back): (i16, i16)
|
||||||
) -> i16 {
|
) -> i16 {
|
||||||
let n = 1 + pairs.len() as i16;
|
let n = 1 + pairs.len() as i16;
|
||||||
|
|
||||||
let target = if ncurses::COLOR_PAIRS() > i32::from(n) {
|
let target = if ncurses::COLOR_PAIRS() > i32::from(n) {
|
||||||
// We still have plenty of space for everyone.
|
// We still have plenty of space for everyone.
|
||||||
n
|
n
|
||||||
@ -104,12 +112,8 @@ impl Backend {
|
|||||||
pairs.retain(|_, &mut v| v != target);
|
pairs.retain(|_, &mut v| v != target);
|
||||||
target
|
target
|
||||||
};
|
};
|
||||||
pairs.insert(pair, target);
|
pairs.insert((front, back), target);
|
||||||
ncurses::init_pair(
|
ncurses::init_pair(target, front, back);
|
||||||
target,
|
|
||||||
find_closest(&pair.front),
|
|
||||||
find_closest(&pair.back),
|
|
||||||
);
|
|
||||||
target
|
target
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -118,11 +122,12 @@ impl Backend {
|
|||||||
let mut pairs = self.pairs.borrow_mut();
|
let mut pairs = self.pairs.borrow_mut();
|
||||||
|
|
||||||
// Find if we have this color in stock
|
// 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!
|
// We got it!
|
||||||
pairs[&pair]
|
pairs[&(front, back)]
|
||||||
} else {
|
} else {
|
||||||
self.insert_color(&mut *pairs, pair)
|
self.insert_color(&mut *pairs, (front, back))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
extern crate pancurses;
|
extern crate pancurses;
|
||||||
|
|
||||||
use self::pancurses::mmask_t;
|
use self::pancurses::mmask_t;
|
||||||
use self::super::{find_closest, split_i32};
|
use self::super::split_i32;
|
||||||
use backend;
|
use backend;
|
||||||
use event::{Event, Key, MouseButton, MouseEvent};
|
use event::{Event, Key, MouseButton, MouseEvent};
|
||||||
use std::cell::{Cell, RefCell};
|
use std::cell::{Cell, RefCell};
|
||||||
@ -13,7 +13,7 @@ use vec::Vec2;
|
|||||||
pub struct Backend {
|
pub struct Backend {
|
||||||
// Used
|
// Used
|
||||||
current_style: Cell<ColorPair>,
|
current_style: Cell<ColorPair>,
|
||||||
pairs: RefCell<HashMap<ColorPair, i32>>,
|
pairs: RefCell<HashMap<(i16, i16), i32>>,
|
||||||
|
|
||||||
key_codes: HashMap<i32, Event>,
|
key_codes: HashMap<i32, Event>,
|
||||||
|
|
||||||
@ -24,6 +24,10 @@ pub struct Backend {
|
|||||||
window: pancurses::Window,
|
window: pancurses::Window,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn find_closest_pair(pair: &ColorPair) -> (i16, i16) {
|
||||||
|
super::find_closest_pair(pair, pancurses::COLORS() as i16)
|
||||||
|
}
|
||||||
|
|
||||||
impl Backend {
|
impl Backend {
|
||||||
pub fn init() -> Box<Self> {
|
pub fn init() -> Box<Self> {
|
||||||
::std::env::set_var("ESCDELAY", "25");
|
::std::env::set_var("ESCDELAY", "25");
|
||||||
@ -62,8 +66,8 @@ impl Backend {
|
|||||||
/// Save a new color pair.
|
/// Save a new color pair.
|
||||||
fn insert_color(
|
fn insert_color(
|
||||||
&self,
|
&self,
|
||||||
pairs: &mut HashMap<ColorPair, i32>,
|
pairs: &mut HashMap<(i16,i16), i32>,
|
||||||
pair: ColorPair,
|
(front, back): (i16, i16),
|
||||||
) -> i32 {
|
) -> i32 {
|
||||||
let n = 1 + pairs.len() as i32;
|
let n = 1 + pairs.len() as i32;
|
||||||
|
|
||||||
@ -78,18 +82,15 @@ impl Backend {
|
|||||||
pairs.retain(|_, &mut v| v != target);
|
pairs.retain(|_, &mut v| v != target);
|
||||||
target
|
target
|
||||||
};
|
};
|
||||||
pairs.insert(pair, target);
|
pairs.insert((front, back), target);
|
||||||
pancurses::init_pair(
|
pancurses::init_pair(target as i16, front, back);
|
||||||
target as i16,
|
|
||||||
find_closest(&pair.front),
|
|
||||||
find_closest(&pair.back),
|
|
||||||
);
|
|
||||||
target
|
target
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Checks the pair in the cache, or re-define a color if needed.
|
/// Checks the pair in the cache, or re-define a color if needed.
|
||||||
fn get_or_create(&self, pair: ColorPair) -> i32 {
|
fn get_or_create(&self, pair: ColorPair) -> i32 {
|
||||||
let mut pairs = self.pairs.borrow_mut();
|
let mut pairs = self.pairs.borrow_mut();
|
||||||
|
let pair = find_closest_pair(&pair);
|
||||||
|
|
||||||
// Find if we have this color in stock
|
// Find if we have this color in stock
|
||||||
if pairs.contains_key(&pair) {
|
if pairs.contains_key(&pair) {
|
||||||
|
Loading…
Reference in New Issue
Block a user