mirror of
https://github.com/ratatui-org/ratatui
synced 2024-11-29 08:00:38 +00:00
Support several modifiers and indexed colors at once
This commit is contained in:
parent
d360cd3434
commit
b7664a4108
17 changed files with 265 additions and 197 deletions
|
@ -97,7 +97,7 @@ fn main() -> Result<(), failure::Error> {
|
|||
.bar_width(5)
|
||||
.bar_gap(3)
|
||||
.style(Style::default().fg(Color::Green))
|
||||
.value_style(Style::default().bg(Color::Green).modifier(Modifier::Bold))
|
||||
.value_style(Style::default().bg(Color::Green).modifier(Modifier::BOLD))
|
||||
.render(&mut f, chunks[0]);
|
||||
BarChart::default()
|
||||
.block(Block::default().title("Data3").borders(Borders::ALL))
|
||||
|
@ -106,7 +106,7 @@ fn main() -> Result<(), failure::Error> {
|
|||
.bar_width(7)
|
||||
.bar_gap(0)
|
||||
.value_style(Style::default().bg(Color::Red))
|
||||
.label_style(Style::default().fg(Color::Cyan).modifier(Modifier::Italic))
|
||||
.label_style(Style::default().fg(Color::Cyan).modifier(Modifier::ITALIC))
|
||||
.render(&mut f, chunks[1]);
|
||||
}
|
||||
})?;
|
||||
|
|
|
@ -54,7 +54,7 @@ fn main() -> Result<(), failure::Error> {
|
|||
Style::default()
|
||||
.fg(Color::White)
|
||||
.bg(Color::Red)
|
||||
.modifier(Modifier::Bold),
|
||||
.modifier(Modifier::BOLD),
|
||||
)
|
||||
.render(&mut f, chunks[1]);
|
||||
}
|
||||
|
|
|
@ -73,14 +73,14 @@ fn main() -> Result<(), failure::Error> {
|
|||
.block(
|
||||
Block::default()
|
||||
.title("Chart")
|
||||
.title_style(Style::default().fg(Color::Cyan).modifier(Modifier::Bold))
|
||||
.title_style(Style::default().fg(Color::Cyan).modifier(Modifier::BOLD))
|
||||
.borders(Borders::ALL),
|
||||
)
|
||||
.x_axis(
|
||||
Axis::default()
|
||||
.title("X Axis")
|
||||
.style(Style::default().fg(Color::Gray))
|
||||
.labels_style(Style::default().modifier(Modifier::Italic))
|
||||
.style(Style::default().fg(Color::White))
|
||||
.labels_style(Style::default().modifier(Modifier::ITALIC))
|
||||
.bounds(app.window)
|
||||
.labels(&[
|
||||
&format!("{}", app.window[0]),
|
||||
|
@ -91,8 +91,8 @@ fn main() -> Result<(), failure::Error> {
|
|||
.y_axis(
|
||||
Axis::default()
|
||||
.title("Y Axis")
|
||||
.style(Style::default().fg(Color::Gray))
|
||||
.labels_style(Style::default().modifier(Modifier::Italic))
|
||||
.style(Style::default().fg(Color::White))
|
||||
.labels_style(Style::default().modifier(Modifier::ITALIC))
|
||||
.bounds([-20.0, 20.0])
|
||||
.labels(&["-20", "0", "20"]),
|
||||
)
|
||||
|
|
|
@ -69,7 +69,7 @@ where
|
|||
Style::default()
|
||||
.fg(Color::Magenta)
|
||||
.bg(Color::Black)
|
||||
.modifier(Modifier::Italic),
|
||||
.modifier(Modifier::ITALIC),
|
||||
)
|
||||
.label(&format!("{} / 100", app.progress))
|
||||
.percent(app.progress)
|
||||
|
@ -107,7 +107,7 @@ where
|
|||
.block(Block::default().borders(Borders::ALL).title("List"))
|
||||
.items(&app.tasks.items)
|
||||
.select(Some(app.tasks.selected))
|
||||
.highlight_style(Style::default().fg(Color::Yellow).modifier(Modifier::Bold))
|
||||
.highlight_style(Style::default().fg(Color::Yellow).modifier(Modifier::BOLD))
|
||||
.highlight_symbol(">")
|
||||
.render(f, chunks[0]);
|
||||
let info_style = Style::default().fg(Color::White);
|
||||
|
@ -138,7 +138,7 @@ where
|
|||
Style::default()
|
||||
.fg(Color::Black)
|
||||
.bg(Color::Green)
|
||||
.modifier(Modifier::Italic),
|
||||
.modifier(Modifier::ITALIC),
|
||||
)
|
||||
.label_style(Style::default().fg(Color::Yellow))
|
||||
.style(Style::default().fg(Color::Green))
|
||||
|
@ -149,14 +149,14 @@ where
|
|||
.block(
|
||||
Block::default()
|
||||
.title("Chart")
|
||||
.title_style(Style::default().fg(Color::Cyan).modifier(Modifier::Bold))
|
||||
.title_style(Style::default().fg(Color::Cyan).modifier(Modifier::BOLD))
|
||||
.borders(Borders::ALL),
|
||||
)
|
||||
.x_axis(
|
||||
Axis::default()
|
||||
.title("X Axis")
|
||||
.style(Style::default().fg(Color::Gray))
|
||||
.labels_style(Style::default().modifier(Modifier::Italic))
|
||||
.labels_style(Style::default().modifier(Modifier::ITALIC))
|
||||
.bounds(app.signals.window)
|
||||
.labels(&[
|
||||
&format!("{}", app.signals.window[0]),
|
||||
|
@ -168,7 +168,7 @@ where
|
|||
Axis::default()
|
||||
.title("Y Axis")
|
||||
.style(Style::default().fg(Color::Gray))
|
||||
.labels_style(Style::default().modifier(Modifier::Italic))
|
||||
.labels_style(Style::default().modifier(Modifier::ITALIC))
|
||||
.bounds([-20.0, 20.0])
|
||||
.labels(&["-20", "0", "20"]),
|
||||
)
|
||||
|
@ -200,13 +200,13 @@ where
|
|||
Text::raw(" "),
|
||||
Text::styled("rainbow", Style::default().fg(Color::Blue)),
|
||||
Text::raw(".\nOh and if you didn't "),
|
||||
Text::styled("notice", Style::default().modifier(Modifier::Italic)),
|
||||
Text::styled("notice", Style::default().modifier(Modifier::ITALIC)),
|
||||
Text::raw(" you can "),
|
||||
Text::styled("automatically", Style::default().modifier(Modifier::Bold)),
|
||||
Text::styled("automatically", Style::default().modifier(Modifier::BOLD)),
|
||||
Text::raw(" "),
|
||||
Text::styled("wrap", Style::default().modifier(Modifier::Invert)),
|
||||
Text::styled("wrap", Style::default().modifier(Modifier::REVERSED)),
|
||||
Text::raw(" your "),
|
||||
Text::styled("text", Style::default().modifier(Modifier::Underline)),
|
||||
Text::styled("text", Style::default().modifier(Modifier::UNDERLINED)),
|
||||
Text::raw(".\nOne more thing is that it should display unicode characters: 10€")
|
||||
];
|
||||
Paragraph::new(text.iter())
|
||||
|
@ -214,7 +214,7 @@ where
|
|||
Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.title("Footer")
|
||||
.title_style(Style::default().fg(Color::Magenta).modifier(Modifier::Bold)),
|
||||
.title_style(Style::default().fg(Color::Magenta).modifier(Modifier::BOLD)),
|
||||
)
|
||||
.wrap(true)
|
||||
.render(f, area);
|
||||
|
|
|
@ -99,7 +99,7 @@ fn main() -> Result<(), failure::Error> {
|
|||
.render(&mut f, chunks[2]);
|
||||
Gauge::default()
|
||||
.block(Block::default().title("Gauge4").borders(Borders::ALL))
|
||||
.style(Style::default().fg(Color::Cyan).modifier(Modifier::Italic))
|
||||
.style(Style::default().fg(Color::Cyan).modifier(Modifier::ITALIC))
|
||||
.percent(app.progress4)
|
||||
.label(&format!("{}/100", app.progress2))
|
||||
.render(&mut f, chunks[3]);
|
||||
|
|
|
@ -102,7 +102,7 @@ fn main() -> Result<(), failure::Error> {
|
|||
.items(&app.items)
|
||||
.select(app.selected)
|
||||
.style(style)
|
||||
.highlight_style(style.fg(Color::LightGreen).modifier(Modifier::Bold))
|
||||
.highlight_style(style.fg(Color::LightGreen).modifier(Modifier::BOLD))
|
||||
.highlight_symbol(">")
|
||||
.render(&mut f, chunks[0]);
|
||||
{
|
||||
|
|
|
@ -60,18 +60,18 @@ fn main() -> Result<(), failure::Error> {
|
|||
Text::styled("This is a line\n", Style::default().bg(Color::Blue)),
|
||||
Text::styled(
|
||||
"This is a longer line\n",
|
||||
Style::default().modifier(Modifier::CrossedOut),
|
||||
Style::default().modifier(Modifier::CROSSED_OUT),
|
||||
),
|
||||
Text::styled(&long_line, Style::default().bg(Color::Green)),
|
||||
Text::styled(
|
||||
"This is a line\n",
|
||||
Style::default().fg(Color::Green).modifier(Modifier::Italic),
|
||||
Style::default().fg(Color::Green).modifier(Modifier::ITALIC),
|
||||
),
|
||||
];
|
||||
|
||||
let block = Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.title_style(Style::default().modifier(Modifier::Bold));
|
||||
.title_style(Style::default().modifier(Modifier::BOLD));
|
||||
Paragraph::new(text.iter())
|
||||
.block(block.clone().title("Left, no wrap"))
|
||||
.alignment(Alignment::Left)
|
||||
|
|
|
@ -53,7 +53,7 @@ fn main() -> Result<(), failure::Error> {
|
|||
// Input
|
||||
loop {
|
||||
terminal.draw(|mut f| {
|
||||
let selected_style = Style::default().fg(Color::Yellow).modifier(Modifier::Bold);
|
||||
let selected_style = Style::default().fg(Color::Yellow).modifier(Modifier::BOLD);
|
||||
let normal_style = Style::default().fg(Color::White);
|
||||
let header = ["Header1", "Header2", "Header3"];
|
||||
let rows = app.items.iter().enumerate().map(|(i, item)| {
|
||||
|
|
|
@ -149,9 +149,8 @@ impl Backend for CrosstermBackend {
|
|||
if let Some(color) = cell.style.bg.into() {
|
||||
s = s.on(color)
|
||||
}
|
||||
if let Some(attr) = cell.style.modifier.into() {
|
||||
s = s.attr(attr)
|
||||
}
|
||||
s.object_style.attrs = cell.style.modifier.into();
|
||||
|
||||
self.crossterm.paint(s).map_err(convert_error)?;
|
||||
}
|
||||
Ok(())
|
||||
|
@ -178,32 +177,59 @@ impl From<Color> for Option<crossterm::Color> {
|
|||
Color::LightMagenta => Some(crossterm::Color::Magenta),
|
||||
Color::LightCyan => Some(crossterm::Color::Cyan),
|
||||
Color::White => Some(crossterm::Color::White),
|
||||
Color::Indexed(i) => Some(crossterm::Color::AnsiValue(i)),
|
||||
Color::Rgb(r, g, b) => Some(crossterm::Color::Rgb { r, g, b }),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Modifier> for Option<crossterm::Attribute> {
|
||||
impl From<Modifier> for Vec<crossterm::Attribute> {
|
||||
#[cfg(unix)]
|
||||
fn from(modifier: Modifier) -> Option<crossterm::Attribute> {
|
||||
match modifier {
|
||||
Modifier::Blink => Some(crossterm::Attribute::SlowBlink),
|
||||
Modifier::Bold => Some(crossterm::Attribute::Bold),
|
||||
Modifier::CrossedOut => Some(crossterm::Attribute::CrossedOut),
|
||||
Modifier::Faint => Some(crossterm::Attribute::Dim),
|
||||
Modifier::Invert => Some(crossterm::Attribute::Reverse),
|
||||
Modifier::Italic => Some(crossterm::Attribute::Italic),
|
||||
Modifier::Underline => Some(crossterm::Attribute::Underlined),
|
||||
_ => None,
|
||||
fn from(modifier: Modifier) -> Vec<crossterm::Attribute> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
if modifier.contains(Modifier::BOLD) {
|
||||
result.push(crossterm::Attribute::Bold)
|
||||
}
|
||||
if modifier.contains(Modifier::DIM) {
|
||||
result.push(crossterm::Attribute::Dim)
|
||||
}
|
||||
if modifier.contains(Modifier::ITALIC) {
|
||||
result.push(crossterm::Attribute::Italic)
|
||||
}
|
||||
if modifier.contains(Modifier::UNDERLINED) {
|
||||
result.push(crossterm::Attribute::Underlined)
|
||||
}
|
||||
if modifier.contains(Modifier::SLOW_BLINK) {
|
||||
result.push(crossterm::Attribute::SlowBlink)
|
||||
}
|
||||
if modifier.contains(Modifier::RAPID_BLINK) {
|
||||
result.push(crossterm::Attribute::RapidBlink)
|
||||
}
|
||||
if modifier.contains(Modifier::REVERSED) {
|
||||
result.push(crossterm::Attribute::Reverse)
|
||||
}
|
||||
if modifier.contains(Modifier::HIDDEN) {
|
||||
result.push(crossterm::Attribute::Hidden)
|
||||
}
|
||||
if modifier.contains(Modifier::CROSSED_OUT) {
|
||||
result.push(crossterm::Attribute::CrossedOut)
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
fn from(modifier: Modifier) -> Option<crossterm::Attribute> {
|
||||
match modifier {
|
||||
Modifier::Bold => Some(crossterm::Attribute::Bold),
|
||||
Modifier::Underline => Some(crossterm::Attribute::Underlined),
|
||||
_ => None,
|
||||
fn from(modifier: Modifier) -> Vec<crossterm::Attribute> {
|
||||
let mut result = Vec::new();
|
||||
|
||||
if modifier.contains(Modifier::BOLD) {
|
||||
result.push(crossterm::Attribute::Bold)
|
||||
}
|
||||
if modifier.contains(Modifier::UNDERLINED) {
|
||||
result.push(crossterm::Attribute::Underlined)
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
|
|
@ -103,6 +103,7 @@ impl Into<rustbox::Color> for Color {
|
|||
Color::Cyan | Color::LightCyan => rustbox::Color::Cyan,
|
||||
Color::White => rustbox::Color::White,
|
||||
Color::Blue | Color::LightBlue => rustbox::Color::Blue,
|
||||
Color::Indexed(i) => rustbox::Color::Byte(i as u16),
|
||||
Color::Rgb(r, g, b) => rustbox::Color::Byte(rgb_to_byte(r, g, b)),
|
||||
}
|
||||
}
|
||||
|
@ -110,11 +111,16 @@ impl Into<rustbox::Color> for Color {
|
|||
|
||||
impl Into<rustbox::Style> for Modifier {
|
||||
fn into(self) -> rustbox::Style {
|
||||
match self {
|
||||
Modifier::Bold => rustbox::RB_BOLD,
|
||||
Modifier::Underline => rustbox::RB_UNDERLINE,
|
||||
Modifier::Invert => rustbox::RB_REVERSE,
|
||||
_ => rustbox::RB_NORMAL,
|
||||
let mut result = rustbox::Style::empty();
|
||||
if self.contains(Modifier::BOLD) {
|
||||
result.insert(rustbox::RB_BOLD);
|
||||
}
|
||||
if self.contains(Modifier::UNDERLINED) {
|
||||
result.insert(rustbox::RB_UNDERLINE);
|
||||
}
|
||||
if self.contains(Modifier::REVERSED) {
|
||||
result.insert(rustbox::RB_REVERSE);
|
||||
}
|
||||
result
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,11 +1,12 @@
|
|||
use log::debug;
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
use std::io::Write;
|
||||
|
||||
use super::Backend;
|
||||
use crate::buffer::Cell;
|
||||
use crate::layout::Rect;
|
||||
use crate::style::{Color, Modifier, Style};
|
||||
use crate::style;
|
||||
|
||||
pub struct TermionBackend<W>
|
||||
where
|
||||
|
@ -74,34 +75,40 @@ where
|
|||
where
|
||||
I: Iterator<Item = (u16, u16, &'a Cell)>,
|
||||
{
|
||||
use std::fmt::Write;
|
||||
|
||||
let mut string = String::with_capacity(content.size_hint().0 * 3);
|
||||
let mut style = Style::default();
|
||||
let mut style = style::Style::default();
|
||||
let mut last_y = 0;
|
||||
let mut last_x = 0;
|
||||
let mut inst = 0;
|
||||
for (x, y, cell) in content {
|
||||
if y != last_y || x != last_x + 1 || inst == 0 {
|
||||
string.push_str(&format!("{}", termion::cursor::Goto(x + 1, y + 1)));
|
||||
write!(string, "{}", termion::cursor::Goto(x + 1, y + 1)).unwrap();
|
||||
inst += 1;
|
||||
}
|
||||
last_x = x;
|
||||
last_y = y;
|
||||
if cell.style.modifier != style.modifier {
|
||||
string.push_str(&cell.style.modifier.termion_modifier());
|
||||
write!(
|
||||
string,
|
||||
"{}",
|
||||
ModifierDiff {
|
||||
from: style.modifier,
|
||||
to: cell.style.modifier
|
||||
}
|
||||
)
|
||||
.unwrap();
|
||||
style.modifier = cell.style.modifier;
|
||||
if style.modifier == Modifier::Reset {
|
||||
style.bg = Color::Reset;
|
||||
style.fg = Color::Reset;
|
||||
}
|
||||
inst += 1;
|
||||
}
|
||||
if cell.style.fg != style.fg {
|
||||
string.push_str(&cell.style.fg.termion_fg());
|
||||
write!(string, "{}", Fg(cell.style.fg)).unwrap();
|
||||
style.fg = cell.style.fg;
|
||||
inst += 1;
|
||||
}
|
||||
if cell.style.bg != style.bg {
|
||||
string.push_str(&cell.style.bg.termion_bg());
|
||||
write!(string, "{}", Bg(cell.style.bg)).unwrap();
|
||||
style.bg = cell.style.bg;
|
||||
inst += 1;
|
||||
}
|
||||
|
@ -113,9 +120,9 @@ where
|
|||
self.stdout,
|
||||
"{}{}{}{}",
|
||||
string,
|
||||
Color::Reset.termion_fg(),
|
||||
Color::Reset.termion_bg(),
|
||||
Modifier::Reset.termion_modifier()
|
||||
Fg(style::Color::Reset),
|
||||
Bg(style::Color::Reset),
|
||||
termion::style::Reset,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -130,102 +137,118 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
macro_rules! termion_fg {
|
||||
($color:ident) => {
|
||||
format!("{}", termion::color::Fg(termion::color::$color))
|
||||
};
|
||||
struct Fg(style::Color);
|
||||
|
||||
struct Bg(style::Color);
|
||||
|
||||
struct ModifierDiff {
|
||||
from: style::Modifier,
|
||||
to: style::Modifier,
|
||||
}
|
||||
|
||||
macro_rules! termion_fg_rgb {
|
||||
($r:expr, $g:expr, $b:expr) => {
|
||||
format!("{}", termion::color::Fg(termion::color::Rgb($r, $g, $b)))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! termion_bg {
|
||||
($color:ident) => {
|
||||
format!("{}", termion::color::Bg(termion::color::$color))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! termion_bg_rgb {
|
||||
($r:expr, $g:expr, $b:expr) => {
|
||||
format!("{}", termion::color::Bg(termion::color::Rgb($r, $g, $b)))
|
||||
};
|
||||
}
|
||||
|
||||
macro_rules! termion_modifier {
|
||||
($style:ident) => {
|
||||
format!("{}", termion::style::$style)
|
||||
};
|
||||
}
|
||||
|
||||
impl Color {
|
||||
pub fn termion_fg(self) -> String {
|
||||
match self {
|
||||
Color::Reset => termion_fg!(Reset),
|
||||
Color::Black => termion_fg!(Black),
|
||||
Color::Red => termion_fg!(Red),
|
||||
Color::Green => termion_fg!(Green),
|
||||
Color::Yellow => termion_fg!(Yellow),
|
||||
Color::Blue => termion_fg!(Blue),
|
||||
Color::Magenta => termion_fg!(Magenta),
|
||||
Color::Cyan => termion_fg!(Cyan),
|
||||
Color::Gray => termion_fg!(White),
|
||||
Color::DarkGray => termion_fg!(LightBlack),
|
||||
Color::LightRed => termion_fg!(LightRed),
|
||||
Color::LightGreen => termion_fg!(LightGreen),
|
||||
Color::LightBlue => termion_fg!(LightBlue),
|
||||
Color::LightYellow => termion_fg!(LightYellow),
|
||||
Color::LightMagenta => termion_fg!(LightMagenta),
|
||||
Color::LightCyan => termion_fg!(LightCyan),
|
||||
Color::White => termion_fg!(LightWhite),
|
||||
Color::Rgb(r, g, b) => termion_fg_rgb!(r, g, b),
|
||||
impl fmt::Display for Fg {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use termion::color::Color;
|
||||
match self.0 {
|
||||
style::Color::Reset => termion::color::Reset.write_fg(f),
|
||||
style::Color::Black => termion::color::Black.write_fg(f),
|
||||
style::Color::Red => termion::color::Red.write_fg(f),
|
||||
style::Color::Green => termion::color::Green.write_fg(f),
|
||||
style::Color::Yellow => termion::color::Yellow.write_fg(f),
|
||||
style::Color::Blue => termion::color::Blue.write_fg(f),
|
||||
style::Color::Magenta => termion::color::Magenta.write_fg(f),
|
||||
style::Color::Cyan => termion::color::Cyan.write_fg(f),
|
||||
style::Color::Gray => termion::color::White.write_fg(f),
|
||||
style::Color::DarkGray => termion::color::LightBlack.write_fg(f),
|
||||
style::Color::LightRed => termion::color::LightRed.write_fg(f),
|
||||
style::Color::LightGreen => termion::color::LightGreen.write_fg(f),
|
||||
style::Color::LightBlue => termion::color::LightBlue.write_fg(f),
|
||||
style::Color::LightYellow => termion::color::LightYellow.write_fg(f),
|
||||
style::Color::LightMagenta => termion::color::LightMagenta.write_fg(f),
|
||||
style::Color::LightCyan => termion::color::LightCyan.write_fg(f),
|
||||
style::Color::White => termion::color::LightWhite.write_fg(f),
|
||||
style::Color::Indexed(i) => termion::color::AnsiValue(i).write_fg(f),
|
||||
style::Color::Rgb(r, g, b) => termion::color::Rgb(r, g, b).write_fg(f),
|
||||
}
|
||||
}
|
||||
pub fn termion_bg(self) -> String {
|
||||
match self {
|
||||
Color::Reset => termion_bg!(Reset),
|
||||
Color::Black => termion_bg!(Black),
|
||||
Color::Red => termion_bg!(Red),
|
||||
Color::Green => termion_bg!(Green),
|
||||
Color::Yellow => termion_bg!(Yellow),
|
||||
Color::Blue => termion_bg!(Blue),
|
||||
Color::Magenta => termion_bg!(Magenta),
|
||||
Color::Cyan => termion_bg!(Cyan),
|
||||
Color::Gray => termion_bg!(White),
|
||||
Color::DarkGray => termion_bg!(LightBlack),
|
||||
Color::LightRed => termion_bg!(LightRed),
|
||||
Color::LightGreen => termion_bg!(LightGreen),
|
||||
Color::LightBlue => termion_bg!(LightBlue),
|
||||
Color::LightYellow => termion_bg!(LightYellow),
|
||||
Color::LightMagenta => termion_bg!(LightMagenta),
|
||||
Color::LightCyan => termion_bg!(LightCyan),
|
||||
Color::White => termion_bg!(LightWhite),
|
||||
Color::Rgb(r, g, b) => termion_bg_rgb!(r, g, b),
|
||||
}
|
||||
impl fmt::Display for Bg {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use termion::color::Color;
|
||||
match self.0 {
|
||||
style::Color::Reset => termion::color::Reset.write_bg(f),
|
||||
style::Color::Black => termion::color::Black.write_bg(f),
|
||||
style::Color::Red => termion::color::Red.write_bg(f),
|
||||
style::Color::Green => termion::color::Green.write_bg(f),
|
||||
style::Color::Yellow => termion::color::Yellow.write_bg(f),
|
||||
style::Color::Blue => termion::color::Blue.write_bg(f),
|
||||
style::Color::Magenta => termion::color::Magenta.write_bg(f),
|
||||
style::Color::Cyan => termion::color::Cyan.write_bg(f),
|
||||
style::Color::Gray => termion::color::White.write_bg(f),
|
||||
style::Color::DarkGray => termion::color::LightBlack.write_bg(f),
|
||||
style::Color::LightRed => termion::color::LightRed.write_bg(f),
|
||||
style::Color::LightGreen => termion::color::LightGreen.write_bg(f),
|
||||
style::Color::LightBlue => termion::color::LightBlue.write_bg(f),
|
||||
style::Color::LightYellow => termion::color::LightYellow.write_bg(f),
|
||||
style::Color::LightMagenta => termion::color::LightMagenta.write_bg(f),
|
||||
style::Color::LightCyan => termion::color::LightCyan.write_bg(f),
|
||||
style::Color::White => termion::color::LightWhite.write_bg(f),
|
||||
style::Color::Indexed(i) => termion::color::AnsiValue(i).write_bg(f),
|
||||
style::Color::Rgb(r, g, b) => termion::color::Rgb(r, g, b).write_bg(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Modifier {
|
||||
pub fn termion_modifier(self) -> String {
|
||||
match self {
|
||||
Modifier::Blink => termion_modifier!(Blink),
|
||||
Modifier::Bold => termion_modifier!(Bold),
|
||||
Modifier::CrossedOut => termion_modifier!(CrossedOut),
|
||||
Modifier::Faint => termion_modifier!(Faint),
|
||||
Modifier::Framed => termion_modifier!(Framed),
|
||||
Modifier::Invert => termion_modifier!(Invert),
|
||||
Modifier::Italic => termion_modifier!(Italic),
|
||||
Modifier::NoBlink => termion_modifier!(NoBlink),
|
||||
Modifier::NoBold => termion_modifier!(NoBold),
|
||||
Modifier::NoCrossedOut => termion_modifier!(NoCrossedOut),
|
||||
Modifier::NoFaint => termion_modifier!(NoFaint),
|
||||
Modifier::NoInvert => termion_modifier!(NoInvert),
|
||||
Modifier::NoItalic => termion_modifier!(NoItalic),
|
||||
Modifier::NoUnderline => termion_modifier!(NoUnderline),
|
||||
Modifier::Reset => termion_modifier!(Reset),
|
||||
Modifier::Underline => termion_modifier!(Underline),
|
||||
impl fmt::Display for ModifierDiff {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
let remove = self.from - self.to;
|
||||
if remove.contains(style::Modifier::REVERSED) {
|
||||
write!(f, "{}", termion::style::NoInvert)?;
|
||||
}
|
||||
if remove.contains(style::Modifier::BOLD) {
|
||||
write!(f, "{}", termion::style::NoBold)?;
|
||||
}
|
||||
if remove.contains(style::Modifier::ITALIC) {
|
||||
write!(f, "{}", termion::style::NoItalic)?;
|
||||
}
|
||||
if remove.contains(style::Modifier::UNDERLINED) {
|
||||
write!(f, "{}", termion::style::NoUnderline)?;
|
||||
}
|
||||
if remove.contains(style::Modifier::DIM) {
|
||||
write!(f, "{}", termion::style::NoFaint)?;
|
||||
}
|
||||
if remove.contains(style::Modifier::CROSSED_OUT) {
|
||||
write!(f, "{}", termion::style::NoCrossedOut)?;
|
||||
}
|
||||
if remove.contains(style::Modifier::SLOW_BLINK)
|
||||
|| remove.contains(style::Modifier::RAPID_BLINK)
|
||||
{
|
||||
write!(f, "{}", termion::style::NoBlink)?;
|
||||
}
|
||||
|
||||
let add = self.to - self.from;
|
||||
if add.contains(style::Modifier::REVERSED) {
|
||||
write!(f, "{}", termion::style::Invert)?;
|
||||
}
|
||||
if add.contains(style::Modifier::BOLD) {
|
||||
write!(f, "{}", termion::style::Bold)?;
|
||||
}
|
||||
if add.contains(style::Modifier::ITALIC) {
|
||||
write!(f, "{}", termion::style::Italic)?;
|
||||
}
|
||||
if add.contains(style::Modifier::UNDERLINED) {
|
||||
write!(f, "{}", termion::style::Underline)?;
|
||||
}
|
||||
if add.contains(style::Modifier::DIM) {
|
||||
write!(f, "{}", termion::style::Faint)?;
|
||||
}
|
||||
if add.contains(style::Modifier::CROSSED_OUT) {
|
||||
write!(f, "{}", termion::style::CrossedOut)?;
|
||||
}
|
||||
if add.contains(style::Modifier::SLOW_BLINK) || add.contains(style::Modifier::RAPID_BLINK) {
|
||||
write!(f, "{}", termion::style::Blink)?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
|
|
@ -88,7 +88,7 @@ impl Default for Cell {
|
|||
/// style: Style {
|
||||
/// fg: Color::Red,
|
||||
/// bg: Color::White,
|
||||
/// modifier: Modifier::Reset
|
||||
/// modifier: Modifier::empty()
|
||||
/// }});
|
||||
/// buf.get_mut(5, 0).set_char('x');
|
||||
/// assert_eq!(buf.get(5, 0).symbol, "x");
|
||||
|
|
95
src/style.rs
95
src/style.rs
|
@ -1,3 +1,5 @@
|
|||
use bitflags::bitflags;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum Color {
|
||||
Reset,
|
||||
|
@ -18,6 +20,7 @@ pub enum Color {
|
|||
LightCyan,
|
||||
White,
|
||||
Rgb(u8, u8, u8),
|
||||
Indexed(u8),
|
||||
}
|
||||
|
||||
impl Color {
|
||||
|
@ -33,62 +36,72 @@ impl Color {
|
|||
Color::Blue => "b",
|
||||
Color::Magenta => "m",
|
||||
Color::Cyan => "c",
|
||||
Color::Gray => "g",
|
||||
Color::DarkGray => "G",
|
||||
Color::Gray => "w",
|
||||
Color::DarkGray => "B",
|
||||
Color::LightRed => "R",
|
||||
Color::LightGreen => "G",
|
||||
Color::LightYellow => "Y",
|
||||
Color::LightBlue => "B",
|
||||
Color::LightMagenta => "M",
|
||||
Color::LightCyan => "C",
|
||||
Color::White => "w",
|
||||
Color::White => "W",
|
||||
Color::Indexed(_) => "i",
|
||||
Color::Rgb(_, _, _) => "o",
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
pub enum Modifier {
|
||||
Blink,
|
||||
Bold,
|
||||
CrossedOut,
|
||||
Faint,
|
||||
Framed,
|
||||
Invert,
|
||||
Italic,
|
||||
NoBlink,
|
||||
NoBold,
|
||||
NoCrossedOut,
|
||||
NoFaint,
|
||||
NoInvert,
|
||||
NoItalic,
|
||||
NoUnderline,
|
||||
Reset,
|
||||
Underline,
|
||||
bitflags! {
|
||||
pub struct Modifier: u16 {
|
||||
const BOLD = 0b0000_0000_0001;
|
||||
const DIM = 0b0000_0000_0010;
|
||||
const ITALIC = 0b0000_0000_0100;
|
||||
const UNDERLINED = 0b0000_0000_1000;
|
||||
const SLOW_BLINK = 0b0000_0001_0000;
|
||||
const RAPID_BLINK = 0b0000_0010_0000;
|
||||
const REVERSED = 0b0000_0100_0000;
|
||||
const HIDDEN = 0b0000_1000_0000;
|
||||
const CROSSED_OUT = 0b0001_0000_0000;
|
||||
}
|
||||
}
|
||||
|
||||
impl Modifier {
|
||||
/// Returns a short code associated with the color, used for debug purpose
|
||||
/// only
|
||||
pub(crate) fn code(&self) -> &str {
|
||||
match self {
|
||||
Modifier::Blink => "bl",
|
||||
Modifier::Bold => "bo",
|
||||
Modifier::CrossedOut => "cr",
|
||||
Modifier::Faint => "fa",
|
||||
Modifier::Framed => "fr",
|
||||
Modifier::Invert => "in",
|
||||
Modifier::Italic => "it",
|
||||
Modifier::NoBlink => "BL",
|
||||
Modifier::NoBold => "BO",
|
||||
Modifier::NoCrossedOut => "CR",
|
||||
Modifier::NoFaint => "FA",
|
||||
Modifier::NoInvert => "IN",
|
||||
Modifier::NoItalic => "IT",
|
||||
Modifier::NoUnderline => "UN",
|
||||
Modifier::Reset => "re",
|
||||
Modifier::Underline => "un",
|
||||
pub(crate) fn code(&self) -> String {
|
||||
use std::fmt::Write;
|
||||
|
||||
let mut result = String::new();
|
||||
|
||||
if self.contains(Modifier::BOLD) {
|
||||
write!(result, "BO").unwrap();
|
||||
}
|
||||
if self.contains(Modifier::DIM) {
|
||||
write!(result, "DI").unwrap();
|
||||
}
|
||||
if self.contains(Modifier::ITALIC) {
|
||||
write!(result, "IT").unwrap();
|
||||
}
|
||||
if self.contains(Modifier::UNDERLINED) {
|
||||
write!(result, "UN").unwrap();
|
||||
}
|
||||
if self.contains(Modifier::SLOW_BLINK) {
|
||||
write!(result, "SL").unwrap();
|
||||
}
|
||||
if self.contains(Modifier::RAPID_BLINK) {
|
||||
write!(result, "RA").unwrap();
|
||||
}
|
||||
if self.contains(Modifier::REVERSED) {
|
||||
write!(result, "RE").unwrap();
|
||||
}
|
||||
if self.contains(Modifier::HIDDEN) {
|
||||
write!(result, "HI").unwrap();
|
||||
}
|
||||
if self.contains(Modifier::CROSSED_OUT) {
|
||||
write!(result, "CR").unwrap();
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -104,7 +117,7 @@ impl Default for Style {
|
|||
Style {
|
||||
fg: Color::Reset,
|
||||
bg: Color::Reset,
|
||||
modifier: Modifier::Reset,
|
||||
modifier: Modifier::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -113,7 +126,7 @@ impl Style {
|
|||
pub fn reset(&mut self) {
|
||||
self.fg = Color::Reset;
|
||||
self.bg = Color::Reset;
|
||||
self.modifier = Modifier::Reset;
|
||||
self.modifier = Modifier::empty();
|
||||
}
|
||||
|
||||
pub fn fg(mut self, color: Color) -> Style {
|
||||
|
|
|
@ -21,7 +21,7 @@ use crate::widgets::{Block, Widget};
|
|||
/// .bar_width(3)
|
||||
/// .bar_gap(1)
|
||||
/// .style(Style::default().fg(Color::Yellow).bg(Color::Red))
|
||||
/// .value_style(Style::default().fg(Color::Red).modifier(Modifier::Bold))
|
||||
/// .value_style(Style::default().fg(Color::Red).modifier(Modifier::BOLD))
|
||||
/// .label_style(Style::default().fg(Color::White))
|
||||
/// .data(&[("B0", 0), ("B1", 2), ("B2", 4), ("B3", 3)])
|
||||
/// .max(4);
|
||||
|
|
|
@ -174,13 +174,13 @@ impl Default for ChartLayout {
|
|||
/// .x_axis(Axis::default()
|
||||
/// .title("X Axis")
|
||||
/// .title_style(Style::default().fg(Color::Red))
|
||||
/// .style(Style::default().fg(Color::Gray))
|
||||
/// .style(Style::default().fg(Color::White))
|
||||
/// .bounds([0.0, 10.0])
|
||||
/// .labels(&["0.0", "5.0", "10.0"]))
|
||||
/// .y_axis(Axis::default()
|
||||
/// .title("Y Axis")
|
||||
/// .title_style(Style::default().fg(Color::Red))
|
||||
/// .style(Style::default().fg(Color::Gray))
|
||||
/// .style(Style::default().fg(Color::White))
|
||||
/// .bounds([0.0, 10.0])
|
||||
/// .labels(&["0.0", "5.0", "10.0"]))
|
||||
/// .datasets(&[Dataset::default()
|
||||
|
|
|
@ -15,7 +15,7 @@ use crate::widgets::{Block, Widget};
|
|||
/// # fn main() {
|
||||
/// Gauge::default()
|
||||
/// .block(Block::default().borders(Borders::ALL).title("Progress"))
|
||||
/// .style(Style::default().fg(Color::White).bg(Color::Black).modifier(Modifier::Italic))
|
||||
/// .style(Style::default().fg(Color::White).bg(Color::Black).modifier(Modifier::ITALIC))
|
||||
/// .percent(20);
|
||||
/// # }
|
||||
/// ```
|
||||
|
|
|
@ -125,7 +125,7 @@ where
|
|||
/// .items(&["Item 1", "Item 2", "Item 3"])
|
||||
/// .select(Some(1))
|
||||
/// .style(Style::default().fg(Color::White))
|
||||
/// .highlight_style(Style::default().modifier(Modifier::Italic))
|
||||
/// .highlight_style(Style::default().modifier(Modifier::ITALIC))
|
||||
/// .highlight_symbol(">>");
|
||||
/// # }
|
||||
/// ```
|
||||
|
|
Loading…
Reference in a new issue