use super::{color, from_screen, Color, ObjectStyle};
use Screen;
use std::fmt::{self, Display, Formatter};
use std::io::Write;
#[cfg(unix)]
use super::Attribute;
pub struct StyledObject<D: Display> {
pub object_style: ObjectStyle,
pub content: D,
}
impl<'a, D: Display + 'a> StyledObject<D> {
pub fn with(mut self, foreground_color: Color) -> StyledObject<D> {
self.object_style = self.object_style.fg(foreground_color);
self
}
pub fn on(mut self, background_color: Color) -> StyledObject<D> {
self.object_style = self.object_style.bg(background_color);
self
}
#[cfg(unix)]
pub fn attr(mut self, attr: Attribute) -> StyledObject<D> {
self.object_style.add_attr(attr);
self
}
#[cfg(unix)]
#[inline(always)]
pub fn bold(self) -> StyledObject<D> {
self.attr(Attribute::Bold)
}
#[cfg(unix)]
#[inline(always)]
pub fn dim(self) -> StyledObject<D> {
self.attr(Attribute::Dim)
}
#[cfg(unix)]
#[inline(always)]
pub fn italic(self) -> StyledObject<D> {
self.attr(Attribute::Italic)
}
#[cfg(unix)]
#[inline(always)]
pub fn underlined(self) -> StyledObject<D> {
self.attr(Attribute::Underlined)
}
#[cfg(unix)]
#[inline(always)]
pub fn slow_blink(self) -> StyledObject<D> {
self.attr(Attribute::SlowBlink)
}
#[cfg(unix)]
#[inline(always)]
pub fn rapid_blink(self) -> StyledObject<D> {
self.attr(Attribute::RapidBlink)
}
#[cfg(unix)]
#[inline(always)]
pub fn reverse(self) -> StyledObject<D> {
self.attr(Attribute::Reverse)
}
#[cfg(unix)]
#[inline(always)]
pub fn hidden(self) -> StyledObject<D> {
self.attr(Attribute::Hidden)
}
#[cfg(unix)]
#[inline(always)]
pub fn crossed_out(self) -> StyledObject<D> {
self.attr(Attribute::CrossedOut)
}
pub fn paint(&self, screen: &Screen) {
let colored_terminal = from_screen(&screen);
let mut reset = true;
if let Some(bg) = self.object_style.bg_color {
colored_terminal.set_bg(bg);
reset = true;
}
if let Some(fg) = self.object_style.fg_color {
colored_terminal.set_fg(fg);
reset = true;
}
#[cfg(unix)]
for attr in self.object_style.attrs.iter() {
screen
.stdout
.write_string(format!(csi!("{}m"), *attr as i16));
reset = true;
}
use std::fmt::Write;
let mut content = String::new();
write!(content, "{}", self.content).unwrap();
screen.stdout.write_string(content);
screen.stdout.flush();
if reset {
colored_terminal.reset();
}
}
pub fn into_displayable(self, screen: &'a Screen) -> DisplayableObject<'a, D> {
DisplayableObject::new(screen, self)
}
}
impl<D: Display> Display for StyledObject<D> {
fn fmt(&self, f: &mut Formatter) -> Result<(), fmt::Error> {
let colored_terminal = color();
let mut reset = true;
if let Some(bg) = self.object_style.bg_color {
colored_terminal.set_bg(bg);
reset = true;
}
if let Some(fg) = self.object_style.fg_color {
colored_terminal.set_fg(fg);
reset = true;
}
#[cfg(unix)]
for attr in self.object_style.attrs.iter() {
write!(f, "{}", format!(csi!("{}m"), *attr as i16));
reset = true;
}
fmt::Display::fmt(&self.content, f)?;
std::io::stdout().flush().expect("Flush stdout failed");
if reset {
colored_terminal.reset();
std::io::stdout().flush().expect("Flush stdout failed");
}
Ok(())
}
}
pub struct DisplayableObject<'a, D: Display + 'a> {
styled_object: StyledObject<D>,
screen: &'a Screen,
}
impl<'a, D: Display + 'a> DisplayableObject<'a, D> {
pub fn new(screen: &'a Screen, styled_object: StyledObject<D>) -> DisplayableObject<'a, D> {
DisplayableObject {
screen,
styled_object,
}
}
}
impl<'a, D: Display + 'a> Display for DisplayableObject<'a, D> {
fn fmt(&self, _f: &mut Formatter) -> Result<(), fmt::Error> {
self.styled_object.paint(&self.screen);
Ok(())
}
}