mirror of
https://github.com/ratatui-org/ratatui
synced 2024-11-26 06:30:29 +00:00
refactor: implement cascading styles
- merge `Style` and `StyleDiff` together. `Style` now is used to activate or deactivate certain style rules not to overidden all of them. - update all impacted widgets, examples and tests.
This commit is contained in:
parent
72ba4ff2d4
commit
0ffea495b1
31 changed files with 533 additions and 723 deletions
|
@ -79,7 +79,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
.block(Block::default().title("Data1").borders(Borders::ALL))
|
||||
.data(&app.data)
|
||||
.bar_width(9)
|
||||
.style(Style::default().fg(Color::Yellow))
|
||||
.bar_style(Style::default().fg(Color::Yellow))
|
||||
.value_style(Style::default().fg(Color::Black).bg(Color::Yellow));
|
||||
f.render_widget(barchart, chunks[0]);
|
||||
|
||||
|
@ -93,18 +93,26 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
.data(&app.data)
|
||||
.bar_width(5)
|
||||
.bar_gap(3)
|
||||
.style(Style::default().fg(Color::Green))
|
||||
.value_style(Style::default().bg(Color::Green).modifier(Modifier::BOLD));
|
||||
.bar_style(Style::default().fg(Color::Green))
|
||||
.value_style(
|
||||
Style::default()
|
||||
.bg(Color::Green)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
);
|
||||
f.render_widget(barchart, chunks[0]);
|
||||
|
||||
let barchart = BarChart::default()
|
||||
.block(Block::default().title("Data3").borders(Borders::ALL))
|
||||
.data(&app.data)
|
||||
.style(Style::default().fg(Color::Red))
|
||||
.bar_style(Style::default().fg(Color::Red))
|
||||
.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)
|
||||
.add_modifier(Modifier::ITALIC),
|
||||
);
|
||||
f.render_widget(barchart, chunks[1]);
|
||||
})?;
|
||||
|
||||
|
|
|
@ -7,7 +7,7 @@ use termion::{event::Key, input::MouseTerminal, raw::IntoRawMode, screen::Altern
|
|||
use tui::{
|
||||
backend::TermionBackend,
|
||||
layout::{Constraint, Direction, Layout},
|
||||
style::{Color, Modifier, Style, StyleDiff},
|
||||
style::{Color, Modifier, Style},
|
||||
text::Span,
|
||||
widgets::{Block, BorderType, Borders},
|
||||
Terminal,
|
||||
|
@ -47,7 +47,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
.split(chunks[0]);
|
||||
let block = Block::default()
|
||||
.title(vec![
|
||||
Span::styled("With", StyleDiff::default().fg(Color::Yellow)),
|
||||
Span::styled("With", Style::default().fg(Color::Yellow)),
|
||||
Span::from(" background"),
|
||||
])
|
||||
.style(Style::default().bg(Color::Green));
|
||||
|
@ -55,7 +55,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
|
||||
let block = Block::default().title(Span::styled(
|
||||
"Styled title",
|
||||
StyleDiff::default()
|
||||
Style::default()
|
||||
.fg(Color::White)
|
||||
.bg(Color::Red)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
|
|
|
@ -10,7 +10,7 @@ use termion::{event::Key, input::MouseTerminal, raw::IntoRawMode, screen::Altern
|
|||
use tui::{
|
||||
backend::TermionBackend,
|
||||
layout::{Constraint, Direction, Layout},
|
||||
style::{Color, Modifier, Style, StyleDiff},
|
||||
style::{Color, Modifier, Style},
|
||||
symbols,
|
||||
text::Span,
|
||||
widgets::{Axis, Block, Borders, Chart, Dataset, GraphType},
|
||||
|
@ -95,12 +95,12 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
let x_labels = vec![
|
||||
Span::styled(
|
||||
format!("{}", app.window[0]),
|
||||
StyleDiff::default().modifier(Modifier::BOLD),
|
||||
Style::default().add_modifier(Modifier::BOLD),
|
||||
),
|
||||
Span::raw(format!("{}", (app.window[0] + app.window[1]) / 2.0)),
|
||||
Span::styled(
|
||||
format!("{}", app.window[1]),
|
||||
StyleDiff::default().modifier(Modifier::BOLD),
|
||||
Style::default().add_modifier(Modifier::BOLD),
|
||||
),
|
||||
];
|
||||
let datasets = vec![
|
||||
|
@ -121,9 +121,9 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
Block::default()
|
||||
.title(Span::styled(
|
||||
"Chart 1",
|
||||
StyleDiff::default()
|
||||
Style::default()
|
||||
.fg(Color::Cyan)
|
||||
.modifier(Modifier::BOLD),
|
||||
.add_modifier(Modifier::BOLD),
|
||||
))
|
||||
.borders(Borders::ALL),
|
||||
)
|
||||
|
@ -139,9 +139,9 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
.title("Y Axis")
|
||||
.style(Style::default().fg(Color::Gray))
|
||||
.labels(vec![
|
||||
Span::styled("-20", StyleDiff::default().modifier(Modifier::BOLD)),
|
||||
Span::styled("-20", Style::default().add_modifier(Modifier::BOLD)),
|
||||
Span::raw("0"),
|
||||
Span::styled("20", StyleDiff::default().modifier(Modifier::BOLD)),
|
||||
Span::styled("20", Style::default().add_modifier(Modifier::BOLD)),
|
||||
])
|
||||
.bounds([-20.0, 20.0]),
|
||||
);
|
||||
|
@ -158,9 +158,9 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
Block::default()
|
||||
.title(Span::styled(
|
||||
"Chart 2",
|
||||
StyleDiff::default()
|
||||
Style::default()
|
||||
.fg(Color::Cyan)
|
||||
.modifier(Modifier::BOLD),
|
||||
.add_modifier(Modifier::BOLD),
|
||||
))
|
||||
.borders(Borders::ALL),
|
||||
)
|
||||
|
@ -170,9 +170,9 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
.style(Style::default().fg(Color::Gray))
|
||||
.bounds([0.0, 5.0])
|
||||
.labels(vec![
|
||||
Span::styled("0", StyleDiff::default().modifier(Modifier::BOLD)),
|
||||
Span::styled("0", Style::default().add_modifier(Modifier::BOLD)),
|
||||
Span::raw("2.5"),
|
||||
Span::styled("5.0", StyleDiff::default().modifier(Modifier::BOLD)),
|
||||
Span::styled("5.0", Style::default().add_modifier(Modifier::BOLD)),
|
||||
]),
|
||||
)
|
||||
.y_axis(
|
||||
|
@ -181,9 +181,9 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
.style(Style::default().fg(Color::Gray))
|
||||
.bounds([0.0, 5.0])
|
||||
.labels(vec![
|
||||
Span::styled("0", StyleDiff::default().modifier(Modifier::BOLD)),
|
||||
Span::styled("0", Style::default().add_modifier(Modifier::BOLD)),
|
||||
Span::raw("2.5"),
|
||||
Span::styled("5.0", StyleDiff::default().modifier(Modifier::BOLD)),
|
||||
Span::styled("5.0", Style::default().add_modifier(Modifier::BOLD)),
|
||||
]),
|
||||
);
|
||||
f.render_widget(chart, chunks[1]);
|
||||
|
@ -199,9 +199,9 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
Block::default()
|
||||
.title(Span::styled(
|
||||
"Chart 3",
|
||||
StyleDiff::default()
|
||||
Style::default()
|
||||
.fg(Color::Cyan)
|
||||
.modifier(Modifier::BOLD),
|
||||
.add_modifier(Modifier::BOLD),
|
||||
))
|
||||
.borders(Borders::ALL),
|
||||
)
|
||||
|
@ -211,9 +211,9 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
.style(Style::default().fg(Color::Gray))
|
||||
.bounds([0.0, 50.0])
|
||||
.labels(vec![
|
||||
Span::styled("0", StyleDiff::default().modifier(Modifier::BOLD)),
|
||||
Span::styled("0", Style::default().add_modifier(Modifier::BOLD)),
|
||||
Span::raw("25"),
|
||||
Span::styled("50", StyleDiff::default().modifier(Modifier::BOLD)),
|
||||
Span::styled("50", Style::default().add_modifier(Modifier::BOLD)),
|
||||
]),
|
||||
)
|
||||
.y_axis(
|
||||
|
@ -222,9 +222,9 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
.style(Style::default().fg(Color::Gray))
|
||||
.bounds([0.0, 5.0])
|
||||
.labels(vec![
|
||||
Span::styled("0", StyleDiff::default().modifier(Modifier::BOLD)),
|
||||
Span::styled("0", Style::default().add_modifier(Modifier::BOLD)),
|
||||
Span::raw("2.5"),
|
||||
Span::styled("5", StyleDiff::default().modifier(Modifier::BOLD)),
|
||||
Span::styled("5", Style::default().add_modifier(Modifier::BOLD)),
|
||||
]),
|
||||
);
|
||||
f.render_widget(chart, chunks[2]);
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use crate::demo::App;
|
||||
use tui::{
|
||||
backend::Backend,
|
||||
layout::{Constraint, Direction, Layout, Rect},
|
||||
style::{Color, Modifier, Style, StyleDiff},
|
||||
style::{Color, Modifier, Style},
|
||||
symbols,
|
||||
text::{Span, Spans},
|
||||
widgets::canvas::{Canvas, Line, Map, MapResolution, Rectangle},
|
||||
|
@ -12,8 +13,6 @@ use tui::{
|
|||
Frame,
|
||||
};
|
||||
|
||||
use crate::demo::App;
|
||||
|
||||
pub fn draw<B: Backend>(f: &mut Frame<B>, app: &mut App) {
|
||||
let chunks = Layout::default()
|
||||
.constraints([Constraint::Length(3), Constraint::Min(0)].as_ref())
|
||||
|
@ -22,17 +21,11 @@ pub fn draw<B: Backend>(f: &mut Frame<B>, app: &mut App) {
|
|||
.tabs
|
||||
.titles
|
||||
.iter()
|
||||
.map(|t| {
|
||||
Spans::from(vec![Span::styled(
|
||||
*t,
|
||||
StyleDiff::default().fg(Color::Green),
|
||||
)])
|
||||
})
|
||||
.map(|t| Spans::from(Span::styled(*t, Style::default().fg(Color::Green))))
|
||||
.collect();
|
||||
let tabs = Tabs::new(titles)
|
||||
.block(Block::default().borders(Borders::ALL).title(app.title))
|
||||
.style(Style::default().fg(Color::Green))
|
||||
.highlight_style_diff(StyleDiff::default().fg(Color::Yellow))
|
||||
.highlight_style(Style::default().fg(Color::Yellow))
|
||||
.select(app.tabs.index);
|
||||
f.render_widget(tabs, chunks[0]);
|
||||
match app.tabs.index {
|
||||
|
@ -75,11 +68,11 @@ where
|
|||
let label = format!("{:.2}%", app.progress * 100.0);
|
||||
let gauge = Gauge::default()
|
||||
.block(Block::default().title("Gauge:"))
|
||||
.style(
|
||||
.gauge_style(
|
||||
Style::default()
|
||||
.fg(Color::Magenta)
|
||||
.bg(Color::Black)
|
||||
.modifier(Modifier::ITALIC | Modifier::BOLD),
|
||||
.add_modifier(Modifier::ITALIC | Modifier::BOLD),
|
||||
)
|
||||
.label(label)
|
||||
.ratio(app.progress);
|
||||
|
@ -129,15 +122,15 @@ where
|
|||
.collect();
|
||||
let tasks = List::new(tasks)
|
||||
.block(Block::default().borders(Borders::ALL).title("List"))
|
||||
.highlight_style_diff(StyleDiff::default().modifier(Modifier::BOLD))
|
||||
.highlight_style(Style::default().add_modifier(Modifier::BOLD))
|
||||
.highlight_symbol("> ");
|
||||
f.render_stateful_widget(tasks, chunks[0], &mut app.tasks.state);
|
||||
|
||||
// Draw logs
|
||||
let info_style = StyleDiff::default().fg(Color::Blue);
|
||||
let warning_style = StyleDiff::default().fg(Color::Yellow);
|
||||
let error_style = StyleDiff::default().fg(Color::Magenta);
|
||||
let critical_style = StyleDiff::default().fg(Color::Red);
|
||||
let info_style = Style::default().fg(Color::Blue);
|
||||
let warning_style = Style::default().fg(Color::Yellow);
|
||||
let error_style = Style::default().fg(Color::Magenta);
|
||||
let critical_style = Style::default().fg(Color::Red);
|
||||
let logs: Vec<ListItem> = app
|
||||
.logs
|
||||
.items
|
||||
|
@ -174,17 +167,17 @@ where
|
|||
Style::default()
|
||||
.fg(Color::Black)
|
||||
.bg(Color::Green)
|
||||
.modifier(Modifier::ITALIC),
|
||||
.add_modifier(Modifier::ITALIC),
|
||||
)
|
||||
.label_style(Style::default().fg(Color::Yellow))
|
||||
.style(Style::default().fg(Color::Green));
|
||||
.bar_style(Style::default().fg(Color::Green));
|
||||
f.render_widget(barchart, chunks[1]);
|
||||
}
|
||||
if app.show_chart {
|
||||
let x_labels = vec![
|
||||
Span::styled(
|
||||
format!("{}", app.signals.window[0]),
|
||||
StyleDiff::default().modifier(Modifier::BOLD),
|
||||
Style::default().add_modifier(Modifier::BOLD),
|
||||
),
|
||||
Span::raw(format!(
|
||||
"{}",
|
||||
|
@ -192,7 +185,7 @@ where
|
|||
)),
|
||||
Span::styled(
|
||||
format!("{}", app.signals.window[1]),
|
||||
StyleDiff::default().modifier(Modifier::BOLD),
|
||||
Style::default().add_modifier(Modifier::BOLD),
|
||||
),
|
||||
];
|
||||
let datasets = vec![
|
||||
|
@ -216,9 +209,9 @@ where
|
|||
Block::default()
|
||||
.title(Span::styled(
|
||||
"Chart",
|
||||
StyleDiff::default()
|
||||
Style::default()
|
||||
.fg(Color::Cyan)
|
||||
.modifier(Modifier::BOLD),
|
||||
.add_modifier(Modifier::BOLD),
|
||||
))
|
||||
.borders(Borders::ALL),
|
||||
)
|
||||
|
@ -235,9 +228,9 @@ where
|
|||
.style(Style::default().fg(Color::Gray))
|
||||
.bounds([-20.0, 20.0])
|
||||
.labels(vec![
|
||||
Span::styled("-20", StyleDiff::default().modifier(Modifier::BOLD)),
|
||||
Span::styled("-20", Style::default().add_modifier(Modifier::BOLD)),
|
||||
Span::raw("0"),
|
||||
Span::styled("20", StyleDiff::default().modifier(Modifier::BOLD)),
|
||||
Span::styled("20", Style::default().add_modifier(Modifier::BOLD)),
|
||||
]),
|
||||
);
|
||||
f.render_widget(chart, chunks[1]);
|
||||
|
@ -253,22 +246,22 @@ where
|
|||
Spans::from(""),
|
||||
Spans::from(vec![
|
||||
Span::from("For example: "),
|
||||
Span::styled("under", StyleDiff::default().fg(Color::Red)),
|
||||
Span::styled("under", Style::default().fg(Color::Red)),
|
||||
Span::raw(" "),
|
||||
Span::styled("the", StyleDiff::default().fg(Color::Green)),
|
||||
Span::styled("the", Style::default().fg(Color::Green)),
|
||||
Span::raw(" "),
|
||||
Span::styled("rainbow", StyleDiff::default().fg(Color::Blue)),
|
||||
Span::styled("rainbow", Style::default().fg(Color::Blue)),
|
||||
Span::raw("."),
|
||||
]),
|
||||
Spans::from(vec![
|
||||
Span::raw("Oh and if you didn't "),
|
||||
Span::styled("notice", StyleDiff::default().modifier(Modifier::ITALIC)),
|
||||
Span::styled("notice", Style::default().add_modifier(Modifier::ITALIC)),
|
||||
Span::raw(" you can "),
|
||||
Span::styled("automatically", StyleDiff::default().modifier(Modifier::BOLD)),
|
||||
Span::styled("automatically", Style::default().add_modifier(Modifier::BOLD)),
|
||||
Span::raw(" "),
|
||||
Span::styled("wrap", StyleDiff::default().modifier(Modifier::REVERSED)),
|
||||
Span::styled("wrap", Style::default().add_modifier(Modifier::REVERSED)),
|
||||
Span::raw(" your "),
|
||||
Span::styled("text", StyleDiff::default().modifier(Modifier::UNDERLINED)),
|
||||
Span::styled("text", Style::default().add_modifier(Modifier::UNDERLINED)),
|
||||
Span::raw(".")
|
||||
]),
|
||||
Spans::from(
|
||||
|
@ -277,9 +270,9 @@ where
|
|||
];
|
||||
let block = Block::default().borders(Borders::ALL).title(Span::styled(
|
||||
"Footer",
|
||||
StyleDiff::default()
|
||||
Style::default()
|
||||
.fg(Color::Magenta)
|
||||
.modifier(Modifier::BOLD),
|
||||
.add_modifier(Modifier::BOLD),
|
||||
));
|
||||
let paragraph = Paragraph::new(text).block(block).wrap(Wrap { trim: true });
|
||||
f.render_widget(paragraph, area);
|
||||
|
@ -296,7 +289,7 @@ where
|
|||
let up_style = Style::default().fg(Color::Green);
|
||||
let failure_style = Style::default()
|
||||
.fg(Color::Red)
|
||||
.modifier(Modifier::RAPID_BLINK | Modifier::CROSSED_OUT);
|
||||
.add_modifier(Modifier::RAPID_BLINK | Modifier::CROSSED_OUT);
|
||||
let header = ["Server", "Location", "Status"];
|
||||
let rows = app.servers.iter().map(|s| {
|
||||
let style = if s.status == "Up" {
|
||||
|
|
|
@ -79,28 +79,32 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
|
||||
let gauge = Gauge::default()
|
||||
.block(Block::default().title("Gauge1").borders(Borders::ALL))
|
||||
.style(Style::default().fg(Color::Yellow))
|
||||
.gauge_style(Style::default().fg(Color::Yellow))
|
||||
.percent(app.progress1);
|
||||
f.render_widget(gauge, chunks[0]);
|
||||
|
||||
let label = format!("{}/100", app.progress2);
|
||||
let gauge = Gauge::default()
|
||||
.block(Block::default().title("Gauge2").borders(Borders::ALL))
|
||||
.style(Style::default().fg(Color::Magenta).bg(Color::Green))
|
||||
.gauge_style(Style::default().fg(Color::Magenta).bg(Color::Green))
|
||||
.percent(app.progress2)
|
||||
.label(label);
|
||||
f.render_widget(gauge, chunks[1]);
|
||||
|
||||
let gauge = Gauge::default()
|
||||
.block(Block::default().title("Gauge3").borders(Borders::ALL))
|
||||
.style(Style::default().fg(Color::Yellow))
|
||||
.gauge_style(Style::default().fg(Color::Yellow))
|
||||
.ratio(app.progress3);
|
||||
f.render_widget(gauge, chunks[2]);
|
||||
|
||||
let label = format!("{}/100", app.progress2);
|
||||
let gauge = Gauge::default()
|
||||
.block(Block::default().title("Gauge4").borders(Borders::ALL))
|
||||
.style(Style::default().fg(Color::Cyan).modifier(Modifier::ITALIC))
|
||||
.block(Block::default().title("Gauge4"))
|
||||
.gauge_style(
|
||||
Style::default()
|
||||
.fg(Color::Cyan)
|
||||
.add_modifier(Modifier::ITALIC),
|
||||
)
|
||||
.percent(app.progress4)
|
||||
.label(label);
|
||||
f.render_widget(gauge, chunks[3]);
|
||||
|
|
|
@ -10,7 +10,7 @@ use termion::{event::Key, input::MouseTerminal, raw::IntoRawMode, screen::Altern
|
|||
use tui::{
|
||||
backend::TermionBackend,
|
||||
layout::{Constraint, Corner, Direction, Layout},
|
||||
style::{Color, Modifier, Style, StyleDiff},
|
||||
style::{Color, Modifier, Style},
|
||||
text::{Span, Spans},
|
||||
widgets::{Block, Borders, List, ListItem},
|
||||
Terminal,
|
||||
|
@ -108,8 +108,6 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
.constraints([Constraint::Percentage(50), Constraint::Percentage(50)].as_ref())
|
||||
.split(f.size());
|
||||
|
||||
let style = Style::default().fg(Color::Black).bg(Color::White);
|
||||
|
||||
let items: Vec<ListItem> = app
|
||||
.items
|
||||
.items
|
||||
|
@ -119,18 +117,17 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
for _ in 0..i.1 {
|
||||
lines.push(Spans::from(Span::styled(
|
||||
"Lorem ipsum dolor sit amet, consectetur adipiscing elit.",
|
||||
StyleDiff::default().modifier(Modifier::ITALIC),
|
||||
Style::default().add_modifier(Modifier::ITALIC),
|
||||
)));
|
||||
}
|
||||
ListItem::new(lines)
|
||||
ListItem::new(lines).style(Style::default().fg(Color::Black).bg(Color::White))
|
||||
})
|
||||
.collect();
|
||||
let items = List::new(items)
|
||||
.block(Block::default().borders(Borders::ALL).title("List"))
|
||||
.style(style)
|
||||
.highlight_style_diff(
|
||||
StyleDiff::default()
|
||||
.fg(Color::LightGreen)
|
||||
.highlight_style(
|
||||
Style::default()
|
||||
.bg(Color::LightGreen)
|
||||
.add_modifier(Modifier::BOLD),
|
||||
)
|
||||
.highlight_symbol(">> ");
|
||||
|
@ -141,18 +138,18 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
.iter()
|
||||
.map(|&(evt, level)| {
|
||||
let s = match level {
|
||||
"CRITICAL" => StyleDiff::default().fg(Color::Red),
|
||||
"ERROR" => StyleDiff::default().fg(Color::Magenta),
|
||||
"WARNING" => StyleDiff::default().fg(Color::Yellow),
|
||||
"INFO" => StyleDiff::default().fg(Color::Blue),
|
||||
_ => StyleDiff::default(),
|
||||
"CRITICAL" => Style::default().fg(Color::Red),
|
||||
"ERROR" => Style::default().fg(Color::Magenta),
|
||||
"WARNING" => Style::default().fg(Color::Yellow),
|
||||
"INFO" => Style::default().fg(Color::Blue),
|
||||
_ => Style::default(),
|
||||
};
|
||||
let header = Spans::from(vec![
|
||||
Span::styled(format!("{:<9}", level), s),
|
||||
Span::raw(" "),
|
||||
Span::styled(
|
||||
"2020-01-01 10:00:00",
|
||||
StyleDiff::default().modifier(Modifier::ITALIC),
|
||||
Style::default().add_modifier(Modifier::ITALIC),
|
||||
),
|
||||
]);
|
||||
let log = Spans::from(vec![Span::raw(evt)]);
|
||||
|
|
|
@ -7,7 +7,7 @@ use termion::{event::Key, input::MouseTerminal, raw::IntoRawMode, screen::Altern
|
|||
use tui::{
|
||||
backend::TermionBackend,
|
||||
layout::{Alignment, Constraint, Direction, Layout},
|
||||
style::{Color, Modifier, Style, StyleDiff},
|
||||
style::{Color, Modifier, Style},
|
||||
text::{Span, Spans},
|
||||
widgets::{Block, Borders, Paragraph, Wrap},
|
||||
Terminal,
|
||||
|
@ -34,7 +34,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
long_line.push('\n');
|
||||
|
||||
let block = Block::default()
|
||||
.style(Style::default().bg(Color::White));
|
||||
.style(Style::default().bg(Color::White).fg(Color::Black));
|
||||
f.render_widget(block, size);
|
||||
|
||||
let chunks = Layout::default()
|
||||
|
@ -53,40 +53,45 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
|
||||
let text = vec![
|
||||
Spans::from("This is a line "),
|
||||
Spans::from(Span::styled("This is a line ", StyleDiff::default().fg(Color::Red))),
|
||||
Spans::from(Span::styled("This is a line", StyleDiff::default().bg(Color::Blue))),
|
||||
Spans::from(Span::styled("This is a line ", Style::default().fg(Color::Red))),
|
||||
Spans::from(Span::styled("This is a line", Style::default().bg(Color::Blue))),
|
||||
Spans::from(Span::styled(
|
||||
"This is a longer line",
|
||||
StyleDiff::default().modifier(Modifier::CROSSED_OUT),
|
||||
Style::default().add_modifier(Modifier::CROSSED_OUT),
|
||||
)),
|
||||
Spans::from(Span::styled(&long_line, StyleDiff::default().bg(Color::Green))),
|
||||
Spans::from(Span::styled(&long_line, Style::default().bg(Color::Green))),
|
||||
Spans::from(Span::styled(
|
||||
"This is a line",
|
||||
StyleDiff::default().fg(Color::Green).modifier(Modifier::ITALIC),
|
||||
Style::default().fg(Color::Green).add_modifier(Modifier::ITALIC),
|
||||
)),
|
||||
];
|
||||
|
||||
let create_block = |title| {
|
||||
Block::default()
|
||||
.borders(Borders::ALL)
|
||||
.title(Span::styled(title, StyleDiff::default().add_modifier(Modifier::BOLD)))
|
||||
.style(Style::default().bg(Color::White).fg(Color::Black))
|
||||
.title(Span::styled(title, Style::default().add_modifier(Modifier::BOLD)))
|
||||
};
|
||||
let paragraph = Paragraph::new(text.clone())
|
||||
.style(Style::default().bg(Color::White).fg(Color::Black))
|
||||
.block(create_block("Left, no wrap"))
|
||||
.alignment(Alignment::Left);
|
||||
f.render_widget(paragraph, chunks[0]);
|
||||
let paragraph = Paragraph::new(text.clone())
|
||||
.style(Style::default().bg(Color::White).fg(Color::Black))
|
||||
.block(create_block("Left, wrap"))
|
||||
.alignment(Alignment::Left)
|
||||
.wrap(Wrap { trim: true });
|
||||
f.render_widget(paragraph, chunks[1]);
|
||||
let paragraph = Paragraph::new(text.clone())
|
||||
.style(Style::default().bg(Color::White).fg(Color::Black))
|
||||
.block(create_block("Center, wrap"))
|
||||
.alignment(Alignment::Center)
|
||||
.wrap(Wrap { trim: true })
|
||||
.scroll((scroll, 0));
|
||||
f.render_widget(paragraph, chunks[2]);
|
||||
let paragraph = Paragraph::new(text)
|
||||
.style(Style::default().bg(Color::White).fg(Color::Black))
|
||||
.block(create_block("Right, wrap"))
|
||||
.alignment(Alignment::Right)
|
||||
.wrap(Wrap { trim: true });
|
||||
|
|
|
@ -7,7 +7,7 @@ use termion::{event::Key, input::MouseTerminal, raw::IntoRawMode, screen::Altern
|
|||
use tui::{
|
||||
backend::TermionBackend,
|
||||
layout::{Alignment, Constraint, Direction, Layout, Rect},
|
||||
style::{Color, Modifier, StyleDiff},
|
||||
style::{Color, Modifier, Style},
|
||||
text::{Span, Spans},
|
||||
widgets::{Block, Borders, Clear, Paragraph, Wrap},
|
||||
Terminal,
|
||||
|
@ -66,16 +66,16 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
|
||||
let text = vec![
|
||||
Spans::from("This is a line "),
|
||||
Spans::from(Span::styled("This is a line ", StyleDiff::default().fg(Color::Red))),
|
||||
Spans::from(Span::styled("This is a line", StyleDiff::default().bg(Color::Blue))),
|
||||
Spans::from(Span::styled("This is a line ", Style::default().fg(Color::Red))),
|
||||
Spans::from(Span::styled("This is a line", Style::default().bg(Color::Blue))),
|
||||
Spans::from(Span::styled(
|
||||
"This is a longer line\n",
|
||||
StyleDiff::default().modifier(Modifier::CROSSED_OUT),
|
||||
Style::default().add_modifier(Modifier::CROSSED_OUT),
|
||||
)),
|
||||
Spans::from(Span::styled(&long_line, StyleDiff::default().bg(Color::Green))),
|
||||
Spans::from(Span::styled(&long_line, Style::default().bg(Color::Green))),
|
||||
Spans::from(Span::styled(
|
||||
"This is a line\n",
|
||||
StyleDiff::default().fg(Color::Green).modifier(Modifier::ITALIC),
|
||||
Style::default().fg(Color::Green).add_modifier(Modifier::ITALIC),
|
||||
)),
|
||||
];
|
||||
|
||||
|
|
|
@ -93,7 +93,9 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
.margin(5)
|
||||
.split(f.size());
|
||||
|
||||
let selected_style = Style::default().fg(Color::Yellow).modifier(Modifier::BOLD);
|
||||
let selected_style = Style::default()
|
||||
.fg(Color::Yellow)
|
||||
.add_modifier(Modifier::BOLD);
|
||||
let normal_style = Style::default().fg(Color::White);
|
||||
let header = ["Header1", "Header2", "Header3"];
|
||||
let rows = table
|
||||
|
|
|
@ -10,7 +10,7 @@ use termion::{event::Key, input::MouseTerminal, raw::IntoRawMode, screen::Altern
|
|||
use tui::{
|
||||
backend::TermionBackend,
|
||||
layout::{Constraint, Direction, Layout},
|
||||
style::{Color, Modifier, Style, StyleDiff},
|
||||
style::{Color, Modifier, Style},
|
||||
text::{Span, Spans},
|
||||
widgets::{Block, Borders, Tabs},
|
||||
Terminal,
|
||||
|
@ -45,7 +45,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
.constraints([Constraint::Length(3), Constraint::Min(0)].as_ref())
|
||||
.split(size);
|
||||
|
||||
let block = Block::default().style(Style::default().bg(Color::White));
|
||||
let block = Block::default().style(Style::default().bg(Color::White).fg(Color::Black));
|
||||
f.render_widget(block, size);
|
||||
let titles = app
|
||||
.tabs
|
||||
|
@ -54,8 +54,8 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
.map(|t| {
|
||||
let (first, rest) = t.split_at(1);
|
||||
Spans::from(vec![
|
||||
Span::styled(first, StyleDiff::default().fg(Color::Yellow)),
|
||||
Span::styled(rest, StyleDiff::default().fg(Color::Green)),
|
||||
Span::styled(first, Style::default().fg(Color::Yellow)),
|
||||
Span::styled(rest, Style::default().fg(Color::Green)),
|
||||
])
|
||||
})
|
||||
.collect();
|
||||
|
@ -63,7 +63,11 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
.block(Block::default().borders(Borders::ALL).title("Tabs"))
|
||||
.select(app.tabs.index)
|
||||
.style(Style::default().fg(Color::Cyan))
|
||||
.highlight_style_diff(StyleDiff::default().modifier(Modifier::BOLD));
|
||||
.highlight_style(
|
||||
Style::default()
|
||||
.add_modifier(Modifier::BOLD)
|
||||
.bg(Color::Black),
|
||||
);
|
||||
f.render_widget(tabs, chunks[0]);
|
||||
let inner = match app.tabs.index {
|
||||
0 => Block::default().title("Inner 0").borders(Borders::ALL),
|
||||
|
|
|
@ -19,8 +19,8 @@ use termion::{event::Key, input::MouseTerminal, raw::IntoRawMode, screen::Altern
|
|||
use tui::{
|
||||
backend::TermionBackend,
|
||||
layout::{Constraint, Direction, Layout},
|
||||
style::{Color, Modifier, Style, StyleDiff},
|
||||
text::{Span, Spans},
|
||||
style::{Color, Modifier, Style},
|
||||
text::{Span, Spans, Text},
|
||||
widgets::{Block, Borders, List, ListItem, Paragraph},
|
||||
Terminal,
|
||||
};
|
||||
|
@ -81,29 +81,38 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||
)
|
||||
.split(f.size());
|
||||
|
||||
let msg = match app.input_mode {
|
||||
InputMode::Normal => vec![
|
||||
Span::raw("Press "),
|
||||
Span::styled("q", StyleDiff::default().add_modifier(Modifier::BOLD)),
|
||||
Span::raw(" to exit, "),
|
||||
Span::styled("e", StyleDiff::default().add_modifier(Modifier::BOLD)),
|
||||
Span::raw(" to start editing."),
|
||||
],
|
||||
InputMode::Editing => vec![
|
||||
Span::raw("Press "),
|
||||
Span::styled("Esc", StyleDiff::default().add_modifier(Modifier::BOLD)),
|
||||
Span::raw(" to stop editing, "),
|
||||
Span::styled("Enter", StyleDiff::default().add_modifier(Modifier::BOLD)),
|
||||
Span::raw(" to record the message"),
|
||||
],
|
||||
let (msg, style) = match app.input_mode {
|
||||
InputMode::Normal => (
|
||||
vec![
|
||||
Span::raw("Press "),
|
||||
Span::styled("q", Style::default().add_modifier(Modifier::BOLD)),
|
||||
Span::raw(" to exit, "),
|
||||
Span::styled("e", Style::default().add_modifier(Modifier::BOLD)),
|
||||
Span::raw(" to start editing."),
|
||||
],
|
||||
Style::default().add_modifier(Modifier::RAPID_BLINK),
|
||||
),
|
||||
InputMode::Editing => (
|
||||
vec![
|
||||
Span::raw("Press "),
|
||||
Span::styled("Esc", Style::default().add_modifier(Modifier::BOLD)),
|
||||
Span::raw(" to stop editing, "),
|
||||
Span::styled("Enter", Style::default().add_modifier(Modifier::BOLD)),
|
||||
Span::raw(" to record the message"),
|
||||
],
|
||||
Style::default(),
|
||||
),
|
||||
};
|
||||
let text = vec![Spans::from(msg)];
|
||||
let mut text = Text::from(Spans::from(msg));
|
||||
text.patch_style(style);
|
||||
let help_message = Paragraph::new(text);
|
||||
f.render_widget(help_message, chunks[0]);
|
||||
|
||||
let text = vec![Spans::from(app.input.as_ref())];
|
||||
let input = Paragraph::new(text)
|
||||
.style(Style::default().fg(Color::Yellow))
|
||||
let input = Paragraph::new(app.input.as_ref())
|
||||
.style(match app.input_mode {
|
||||
InputMode::Normal => Style::default(),
|
||||
InputMode::Editing => Style::default().fg(Color::Yellow),
|
||||
})
|
||||
.block(Block::default().borders(Borders::ALL).title("Input"));
|
||||
f.render_widget(input, chunks[1]);
|
||||
match app.input_mode {
|
||||
|
|
|
@ -67,7 +67,9 @@ impl Events {
|
|||
};
|
||||
let tick_handle = {
|
||||
thread::spawn(move || loop {
|
||||
tx.send(Event::Tick).unwrap();
|
||||
if tx.send(Event::Tick).is_err() {
|
||||
break;
|
||||
}
|
||||
thread::sleep(config.tick_rate);
|
||||
})
|
||||
};
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
use std::{
|
||||
fmt,
|
||||
io::{self, Write},
|
||||
use crate::{
|
||||
backend::Backend,
|
||||
buffer::Cell,
|
||||
layout::Rect,
|
||||
style::{Color, Modifier},
|
||||
};
|
||||
|
||||
use crossterm::{
|
||||
cursor::{Hide, MoveTo, Show},
|
||||
execute, queue,
|
||||
|
@ -12,10 +13,10 @@ use crossterm::{
|
|||
},
|
||||
terminal::{self, Clear, ClearType},
|
||||
};
|
||||
|
||||
use crate::backend::Backend;
|
||||
use crate::style::{Color, Modifier};
|
||||
use crate::{buffer::Cell, layout::Rect, style};
|
||||
use std::{
|
||||
fmt,
|
||||
io::{self, Write},
|
||||
};
|
||||
|
||||
pub struct CrosstermBackend<W: Write> {
|
||||
buffer: W,
|
||||
|
@ -54,41 +55,39 @@ where
|
|||
use fmt::Write;
|
||||
|
||||
let mut string = String::with_capacity(content.size_hint().0 * 3);
|
||||
let mut style = style::Style::default();
|
||||
let mut fg = Color::Reset;
|
||||
let mut bg = Color::Reset;
|
||||
let mut modifier = Modifier::empty();
|
||||
let mut last_y = 0;
|
||||
let mut last_x = 0;
|
||||
let mut inst = 0;
|
||||
|
||||
map_error(queue!(string, MoveTo(0, 0)))?;
|
||||
for (x, y, cell) in content {
|
||||
if y != last_y || x != last_x + 1 || inst == 0 {
|
||||
if y != last_y || x != last_x + 1 {
|
||||
map_error(queue!(string, MoveTo(x, y)))?;
|
||||
}
|
||||
last_x = x;
|
||||
last_y = y;
|
||||
if cell.style.modifier != style.modifier {
|
||||
if cell.modifier != modifier {
|
||||
let diff = ModifierDiff {
|
||||
from: style.modifier,
|
||||
to: cell.style.modifier,
|
||||
from: modifier,
|
||||
to: cell.modifier,
|
||||
};
|
||||
diff.queue(&mut string)?;
|
||||
inst += 1;
|
||||
style.modifier = cell.style.modifier;
|
||||
modifier = cell.modifier;
|
||||
}
|
||||
if cell.style.fg != style.fg {
|
||||
let color = CColor::from(cell.style.fg);
|
||||
if cell.fg != fg {
|
||||
let color = CColor::from(cell.fg);
|
||||
map_error(queue!(string, SetForegroundColor(color)))?;
|
||||
style.fg = cell.style.fg;
|
||||
inst += 1;
|
||||
fg = cell.fg;
|
||||
}
|
||||
if cell.style.bg != style.bg {
|
||||
let color = CColor::from(cell.style.bg);
|
||||
if cell.bg != bg {
|
||||
let color = CColor::from(cell.bg);
|
||||
map_error(queue!(string, SetBackgroundColor(color)))?;
|
||||
style.bg = cell.style.bg;
|
||||
inst += 1;
|
||||
bg = cell.bg;
|
||||
}
|
||||
|
||||
string.push_str(&cell.symbol);
|
||||
inst += 1;
|
||||
}
|
||||
|
||||
map_error(queue!(
|
||||
|
|
|
@ -3,7 +3,7 @@ use std::io;
|
|||
use crate::backend::Backend;
|
||||
use crate::buffer::Cell;
|
||||
use crate::layout::Rect;
|
||||
use crate::style::{Color, Modifier, Style};
|
||||
use crate::style::{Color, Modifier};
|
||||
use crate::symbols::{bar, block};
|
||||
#[cfg(unix)]
|
||||
use crate::symbols::{line, DOT};
|
||||
|
@ -41,44 +41,41 @@ impl Backend for CursesBackend {
|
|||
{
|
||||
let mut last_col = 0;
|
||||
let mut last_row = 0;
|
||||
let mut style = Style {
|
||||
fg: Color::Reset,
|
||||
bg: Color::Reset,
|
||||
modifier: Modifier::empty(),
|
||||
};
|
||||
let mut fg = Color::Reset;
|
||||
let mut bg = Color::Reset;
|
||||
let mut modifier = Modifier::empty();
|
||||
let mut curses_style = CursesStyle {
|
||||
fg: easycurses::Color::White,
|
||||
bg: easycurses::Color::Black,
|
||||
};
|
||||
let mut update_color = false;
|
||||
for (col, row, cell) in content {
|
||||
// eprintln!("{:?}", cell);
|
||||
if row != last_row || col != last_col + 1 {
|
||||
self.curses.move_rc(i32::from(row), i32::from(col));
|
||||
}
|
||||
last_col = col;
|
||||
last_row = row;
|
||||
if cell.style.modifier != style.modifier {
|
||||
apply_modifier_diff(&mut self.curses.win, style.modifier, cell.style.modifier);
|
||||
style.modifier = cell.style.modifier;
|
||||
if cell.modifier != modifier {
|
||||
apply_modifier_diff(&mut self.curses.win, modifier, cell.modifier);
|
||||
modifier = cell.modifier;
|
||||
};
|
||||
if cell.style.fg != style.fg {
|
||||
if cell.fg != fg {
|
||||
update_color = true;
|
||||
if let Some(ccolor) = cell.style.fg.into() {
|
||||
style.fg = cell.style.fg;
|
||||
if let Some(ccolor) = cell.fg.into() {
|
||||
fg = cell.fg;
|
||||
curses_style.fg = ccolor;
|
||||
} else {
|
||||
style.fg = Color::White;
|
||||
fg = Color::White;
|
||||
curses_style.fg = easycurses::Color::White;
|
||||
}
|
||||
};
|
||||
if cell.style.bg != style.bg {
|
||||
if cell.bg != bg {
|
||||
update_color = true;
|
||||
if let Some(ccolor) = cell.style.bg.into() {
|
||||
style.bg = cell.style.bg;
|
||||
if let Some(ccolor) = cell.bg.into() {
|
||||
bg = cell.bg;
|
||||
curses_style.bg = ccolor;
|
||||
} else {
|
||||
style.bg = Color::Black;
|
||||
bg = Color::Black;
|
||||
curses_style.bg = easycurses::Color::Black;
|
||||
}
|
||||
};
|
||||
|
|
|
@ -34,9 +34,9 @@ impl Backend for RustboxBackend {
|
|||
self.rustbox.print(
|
||||
x as usize,
|
||||
y as usize,
|
||||
cell.style.modifier.into(),
|
||||
cell.style.fg.into(),
|
||||
cell.style.bg.into(),
|
||||
cell.modifier.into(),
|
||||
cell.fg.into(),
|
||||
cell.bg.into(),
|
||||
&cell.symbol,
|
||||
);
|
||||
}
|
||||
|
|
|
@ -3,9 +3,11 @@ use std::io;
|
|||
use std::io::Write;
|
||||
|
||||
use super::Backend;
|
||||
use crate::buffer::Cell;
|
||||
use crate::layout::Rect;
|
||||
use crate::style;
|
||||
use crate::{
|
||||
buffer::Cell,
|
||||
layout::Rect,
|
||||
style::{Color, Modifier},
|
||||
};
|
||||
|
||||
pub struct TermionBackend<W>
|
||||
where
|
||||
|
@ -77,49 +79,46 @@ where
|
|||
use std::fmt::Write;
|
||||
|
||||
let mut string = String::with_capacity(content.size_hint().0 * 3);
|
||||
let mut style = style::Style::default();
|
||||
let mut fg = Color::Reset;
|
||||
let mut bg = Color::Reset;
|
||||
let mut modifier = Modifier::empty();
|
||||
let mut last_y = 0;
|
||||
let mut last_x = 0;
|
||||
let mut inst = 0;
|
||||
write!(string, "{}", termion::cursor::Goto(1, 1)).unwrap();
|
||||
for (x, y, cell) in content {
|
||||
if y != last_y || x != last_x + 1 || inst == 0 {
|
||||
if y != last_y || x != last_x + 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 {
|
||||
if cell.modifier != modifier {
|
||||
write!(
|
||||
string,
|
||||
"{}",
|
||||
ModifierDiff {
|
||||
from: style.modifier,
|
||||
to: cell.style.modifier
|
||||
from: modifier,
|
||||
to: cell.modifier
|
||||
}
|
||||
)
|
||||
.unwrap();
|
||||
style.modifier = cell.style.modifier;
|
||||
inst += 1;
|
||||
modifier = cell.modifier;
|
||||
}
|
||||
if cell.style.fg != style.fg {
|
||||
write!(string, "{}", Fg(cell.style.fg)).unwrap();
|
||||
style.fg = cell.style.fg;
|
||||
inst += 1;
|
||||
if cell.fg != fg {
|
||||
write!(string, "{}", Fg(cell.fg)).unwrap();
|
||||
fg = cell.fg;
|
||||
}
|
||||
if cell.style.bg != style.bg {
|
||||
write!(string, "{}", Bg(cell.style.bg)).unwrap();
|
||||
style.bg = cell.style.bg;
|
||||
inst += 1;
|
||||
if cell.bg != bg {
|
||||
write!(string, "{}", Bg(cell.bg)).unwrap();
|
||||
bg = cell.bg;
|
||||
}
|
||||
string.push_str(&cell.symbol);
|
||||
inst += 1;
|
||||
}
|
||||
write!(
|
||||
self.stdout,
|
||||
"{}{}{}{}",
|
||||
string,
|
||||
Fg(style::Color::Reset),
|
||||
Bg(style::Color::Reset),
|
||||
Fg(Color::Reset),
|
||||
Bg(Color::Reset),
|
||||
termion::style::Reset,
|
||||
)
|
||||
}
|
||||
|
@ -135,64 +134,64 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
struct Fg(style::Color);
|
||||
struct Fg(Color);
|
||||
|
||||
struct Bg(style::Color);
|
||||
struct Bg(Color);
|
||||
|
||||
struct ModifierDiff {
|
||||
from: style::Modifier,
|
||||
to: style::Modifier,
|
||||
from: Modifier,
|
||||
to: Modifier,
|
||||
}
|
||||
|
||||
impl fmt::Display for Fg {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use termion::color::Color;
|
||||
use termion::color::Color as TermionColor;
|
||||
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),
|
||||
Color::Reset => termion::color::Reset.write_fg(f),
|
||||
Color::Black => termion::color::Black.write_fg(f),
|
||||
Color::Red => termion::color::Red.write_fg(f),
|
||||
Color::Green => termion::color::Green.write_fg(f),
|
||||
Color::Yellow => termion::color::Yellow.write_fg(f),
|
||||
Color::Blue => termion::color::Blue.write_fg(f),
|
||||
Color::Magenta => termion::color::Magenta.write_fg(f),
|
||||
Color::Cyan => termion::color::Cyan.write_fg(f),
|
||||
Color::Gray => termion::color::White.write_fg(f),
|
||||
Color::DarkGray => termion::color::LightBlack.write_fg(f),
|
||||
Color::LightRed => termion::color::LightRed.write_fg(f),
|
||||
Color::LightGreen => termion::color::LightGreen.write_fg(f),
|
||||
Color::LightBlue => termion::color::LightBlue.write_fg(f),
|
||||
Color::LightYellow => termion::color::LightYellow.write_fg(f),
|
||||
Color::LightMagenta => termion::color::LightMagenta.write_fg(f),
|
||||
Color::LightCyan => termion::color::LightCyan.write_fg(f),
|
||||
Color::White => termion::color::LightWhite.write_fg(f),
|
||||
Color::Indexed(i) => termion::color::AnsiValue(i).write_fg(f),
|
||||
Color::Rgb(r, g, b) => termion::color::Rgb(r, g, b).write_fg(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
impl fmt::Display for Bg {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
use termion::color::Color;
|
||||
use termion::color::Color as TermionColor;
|
||||
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),
|
||||
Color::Reset => termion::color::Reset.write_bg(f),
|
||||
Color::Black => termion::color::Black.write_bg(f),
|
||||
Color::Red => termion::color::Red.write_bg(f),
|
||||
Color::Green => termion::color::Green.write_bg(f),
|
||||
Color::Yellow => termion::color::Yellow.write_bg(f),
|
||||
Color::Blue => termion::color::Blue.write_bg(f),
|
||||
Color::Magenta => termion::color::Magenta.write_bg(f),
|
||||
Color::Cyan => termion::color::Cyan.write_bg(f),
|
||||
Color::Gray => termion::color::White.write_bg(f),
|
||||
Color::DarkGray => termion::color::LightBlack.write_bg(f),
|
||||
Color::LightRed => termion::color::LightRed.write_bg(f),
|
||||
Color::LightGreen => termion::color::LightGreen.write_bg(f),
|
||||
Color::LightBlue => termion::color::LightBlue.write_bg(f),
|
||||
Color::LightYellow => termion::color::LightYellow.write_bg(f),
|
||||
Color::LightMagenta => termion::color::LightMagenta.write_bg(f),
|
||||
Color::LightCyan => termion::color::LightCyan.write_bg(f),
|
||||
Color::White => termion::color::LightWhite.write_bg(f),
|
||||
Color::Indexed(i) => termion::color::AnsiValue(i).write_bg(f),
|
||||
Color::Rgb(r, g, b) => termion::color::Rgb(r, g, b).write_bg(f),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -200,63 +199,61 @@ impl fmt::Display for Bg {
|
|||
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) {
|
||||
if remove.contains(Modifier::REVERSED) {
|
||||
write!(f, "{}", termion::style::NoInvert)?;
|
||||
}
|
||||
if remove.contains(style::Modifier::BOLD) {
|
||||
if remove.contains(Modifier::BOLD) {
|
||||
// XXX: the termion NoBold flag actually enables double-underline on ECMA-48 compliant
|
||||
// terminals, and NoFaint additionally disables bold... so we use this trick to get
|
||||
// the right semantics.
|
||||
write!(f, "{}", termion::style::NoFaint)?;
|
||||
|
||||
if self.to.contains(style::Modifier::DIM) {
|
||||
if self.to.contains(Modifier::DIM) {
|
||||
write!(f, "{}", termion::style::Faint)?;
|
||||
}
|
||||
}
|
||||
if remove.contains(style::Modifier::ITALIC) {
|
||||
if remove.contains(Modifier::ITALIC) {
|
||||
write!(f, "{}", termion::style::NoItalic)?;
|
||||
}
|
||||
if remove.contains(style::Modifier::UNDERLINED) {
|
||||
if remove.contains(Modifier::UNDERLINED) {
|
||||
write!(f, "{}", termion::style::NoUnderline)?;
|
||||
}
|
||||
if remove.contains(style::Modifier::DIM) {
|
||||
if remove.contains(Modifier::DIM) {
|
||||
write!(f, "{}", termion::style::NoFaint)?;
|
||||
|
||||
// XXX: the NoFaint flag additionally disables bold as well, so we need to re-enable it
|
||||
// here if we want it.
|
||||
if self.to.contains(style::Modifier::BOLD) {
|
||||
if self.to.contains(Modifier::BOLD) {
|
||||
write!(f, "{}", termion::style::Bold)?;
|
||||
}
|
||||
}
|
||||
if remove.contains(style::Modifier::CROSSED_OUT) {
|
||||
if remove.contains(Modifier::CROSSED_OUT) {
|
||||
write!(f, "{}", termion::style::NoCrossedOut)?;
|
||||
}
|
||||
if remove.contains(style::Modifier::SLOW_BLINK)
|
||||
|| remove.contains(style::Modifier::RAPID_BLINK)
|
||||
{
|
||||
if remove.contains(Modifier::SLOW_BLINK) || remove.contains(Modifier::RAPID_BLINK) {
|
||||
write!(f, "{}", termion::style::NoBlink)?;
|
||||
}
|
||||
|
||||
let add = self.to - self.from;
|
||||
if add.contains(style::Modifier::REVERSED) {
|
||||
if add.contains(Modifier::REVERSED) {
|
||||
write!(f, "{}", termion::style::Invert)?;
|
||||
}
|
||||
if add.contains(style::Modifier::BOLD) {
|
||||
if add.contains(Modifier::BOLD) {
|
||||
write!(f, "{}", termion::style::Bold)?;
|
||||
}
|
||||
if add.contains(style::Modifier::ITALIC) {
|
||||
if add.contains(Modifier::ITALIC) {
|
||||
write!(f, "{}", termion::style::Italic)?;
|
||||
}
|
||||
if add.contains(style::Modifier::UNDERLINED) {
|
||||
if add.contains(Modifier::UNDERLINED) {
|
||||
write!(f, "{}", termion::style::Underline)?;
|
||||
}
|
||||
if add.contains(style::Modifier::DIM) {
|
||||
if add.contains(Modifier::DIM) {
|
||||
write!(f, "{}", termion::style::Faint)?;
|
||||
}
|
||||
if add.contains(style::Modifier::CROSSED_OUT) {
|
||||
if add.contains(Modifier::CROSSED_OUT) {
|
||||
write!(f, "{}", termion::style::CrossedOut)?;
|
||||
}
|
||||
if add.contains(style::Modifier::SLOW_BLINK) || add.contains(style::Modifier::RAPID_BLINK) {
|
||||
if add.contains(Modifier::SLOW_BLINK) || add.contains(Modifier::RAPID_BLINK) {
|
||||
write!(f, "{}", termion::style::Blink)?;
|
||||
}
|
||||
|
||||
|
|
|
@ -106,8 +106,7 @@ impl Backend for TestBackend {
|
|||
{
|
||||
for (x, y, c) in content {
|
||||
let cell = self.buffer.get_mut(x, y);
|
||||
cell.symbol = c.symbol.clone();
|
||||
cell.style = c.style;
|
||||
*cell = c.clone();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -11,7 +11,9 @@ use unicode_width::UnicodeWidthStr;
|
|||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Cell {
|
||||
pub symbol: String,
|
||||
pub style: Style,
|
||||
pub fg: Color,
|
||||
pub bg: Color,
|
||||
pub modifier: Modifier,
|
||||
}
|
||||
|
||||
impl Cell {
|
||||
|
@ -28,29 +30,33 @@ impl Cell {
|
|||
}
|
||||
|
||||
pub fn set_fg(&mut self, color: Color) -> &mut Cell {
|
||||
self.style.fg = color;
|
||||
self.fg = color;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_bg(&mut self, color: Color) -> &mut Cell {
|
||||
self.style.bg = color;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_modifier(&mut self, modifier: Modifier) -> &mut Cell {
|
||||
self.style.modifier = modifier;
|
||||
self.bg = color;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn set_style(&mut self, style: Style) -> &mut Cell {
|
||||
self.style = style;
|
||||
if let Some(c) = style.fg {
|
||||
self.fg = c;
|
||||
}
|
||||
if let Some(c) = style.bg {
|
||||
self.bg = c;
|
||||
}
|
||||
self.modifier.insert(style.add_modifier);
|
||||
self.modifier.remove(style.sub_modifier);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn reset(&mut self) {
|
||||
self.symbol.clear();
|
||||
self.symbol.push(' ');
|
||||
self.style.reset();
|
||||
self.fg = Color::Reset;
|
||||
self.bg = Color::Reset;
|
||||
self.modifier = Modifier::empty();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,7 +64,9 @@ impl Default for Cell {
|
|||
fn default() -> Cell {
|
||||
Cell {
|
||||
symbol: " ".into(),
|
||||
style: Default::default(),
|
||||
fg: Color::Reset,
|
||||
bg: Color::Reset,
|
||||
modifier: Modifier::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -83,11 +91,10 @@ impl Default for Cell {
|
|||
/// buf.set_string(3, 0, "string", Style::default().fg(Color::Red).bg(Color::White));
|
||||
/// assert_eq!(buf.get(5, 0), &Cell{
|
||||
/// symbol: String::from("r"),
|
||||
/// style: Style {
|
||||
/// fg: Color::Red,
|
||||
/// bg: Color::White,
|
||||
/// modifier: Modifier::empty()
|
||||
/// }});
|
||||
/// fg: Color::Red,
|
||||
/// bg: Color::White,
|
||||
/// modifier: Modifier::empty()
|
||||
/// });
|
||||
/// buf.get_mut(5, 0).set_char('x');
|
||||
/// assert_eq!(buf.get(5, 0).symbol, "x");
|
||||
/// ```
|
||||
|
@ -299,14 +306,7 @@ impl Buffer {
|
|||
(x_offset as u16, y)
|
||||
}
|
||||
|
||||
pub fn set_spans<'a>(
|
||||
&mut self,
|
||||
x: u16,
|
||||
y: u16,
|
||||
spans: &Spans<'a>,
|
||||
width: u16,
|
||||
base_style: Style,
|
||||
) -> (u16, u16) {
|
||||
pub fn set_spans<'a>(&mut self, x: u16, y: u16, spans: &Spans<'a>, width: u16) -> (u16, u16) {
|
||||
let mut remaining_width = width;
|
||||
let mut x = x;
|
||||
for span in &spans.0 {
|
||||
|
@ -318,7 +318,7 @@ impl Buffer {
|
|||
y,
|
||||
span.content.as_ref(),
|
||||
remaining_width as usize,
|
||||
base_style.patch(span.style_diff),
|
||||
span.style,
|
||||
);
|
||||
let w = pos.0.saturating_sub(x);
|
||||
x = pos.0;
|
||||
|
@ -327,23 +327,14 @@ impl Buffer {
|
|||
(x, y)
|
||||
}
|
||||
|
||||
pub fn set_span<'a>(
|
||||
&mut self,
|
||||
x: u16,
|
||||
y: u16,
|
||||
span: &Span<'a>,
|
||||
width: u16,
|
||||
base_style: Style,
|
||||
) -> (u16, u16) {
|
||||
self.set_stringn(
|
||||
x,
|
||||
y,
|
||||
span.content.as_ref(),
|
||||
width as usize,
|
||||
base_style.patch(span.style_diff),
|
||||
)
|
||||
pub fn set_span<'a>(&mut self, x: u16, y: u16, span: &Span<'a>, width: u16) -> (u16, u16) {
|
||||
self.set_stringn(x, y, span.content.as_ref(), width as usize, span.style)
|
||||
}
|
||||
|
||||
#[deprecated(
|
||||
since = "0.10.0",
|
||||
note = "You should use styling capabilities of `Buffer::set_style`"
|
||||
)]
|
||||
pub fn set_background(&mut self, area: Rect, color: Color) {
|
||||
for y in area.top()..area.bottom() {
|
||||
for x in area.left()..area.right() {
|
||||
|
@ -352,6 +343,14 @@ impl Buffer {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn set_style(&mut self, area: Rect, style: Style) {
|
||||
for y in area.top()..area.bottom() {
|
||||
for x in area.left()..area.right() {
|
||||
self.get_mut(x, y).set_style(style);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Resize the buffer so that the mapped area matches the given area and that the buffer
|
||||
/// length is equal to area.width * area.height
|
||||
pub fn resize(&mut self, area: Rect) {
|
||||
|
|
315
src/style.rs
315
src/style.rs
|
@ -58,192 +58,43 @@ bitflags! {
|
|||
///
|
||||
/// ```rust
|
||||
/// # use tui::style::{Color, Modifier, Style};
|
||||
/// // Using the raw struct initialization:
|
||||
/// let s = Style {
|
||||
/// fg: Color::Black,
|
||||
/// bg: Color::Green,
|
||||
/// modifier: Modifier::ITALIC | Modifier::BOLD
|
||||
/// };
|
||||
/// // Using the provided builder pattern:
|
||||
/// let s = Style::default()
|
||||
/// Style::default()
|
||||
/// .fg(Color::Black)
|
||||
/// .bg(Color::Green)
|
||||
/// .modifier(Modifier::ITALIC | Modifier::BOLD);
|
||||
/// .add_modifier(Modifier::ITALIC | Modifier::BOLD);
|
||||
/// ```
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct Style {
|
||||
/// The foreground color.
|
||||
pub fg: Color,
|
||||
/// The background color.
|
||||
pub bg: Color,
|
||||
/// The emphasis applied to the text graphemes.
|
||||
pub modifier: Modifier,
|
||||
pub fg: Option<Color>,
|
||||
pub bg: Option<Color>,
|
||||
pub add_modifier: Modifier,
|
||||
pub sub_modifier: Modifier,
|
||||
}
|
||||
|
||||
impl Default for Style {
|
||||
fn default() -> Style {
|
||||
Style::new()
|
||||
Style {
|
||||
fg: None,
|
||||
bg: None,
|
||||
add_modifier: Modifier::empty(),
|
||||
sub_modifier: Modifier::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Style {
|
||||
pub const fn new() -> Self {
|
||||
Style {
|
||||
fg: Color::Reset,
|
||||
bg: Color::Reset,
|
||||
modifier: Modifier::empty(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Reinitializes the style properties. Both colors are put back to `Color::Reset` while
|
||||
/// all modifiers are cleared.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::style::{Color, Modifier, Style};
|
||||
/// let mut s = Style::default().fg(Color::Red).bg(Color::Green).modifier(Modifier::BOLD);
|
||||
/// s.reset();
|
||||
/// assert_eq!(s.fg, Color::Reset);
|
||||
/// assert_eq!(s.bg, Color::Reset);
|
||||
/// assert_eq!(s.modifier, Modifier::empty());
|
||||
/// ```
|
||||
pub fn reset(&mut self) {
|
||||
self.fg = Color::Reset;
|
||||
self.bg = Color::Reset;
|
||||
self.modifier = Modifier::empty();
|
||||
}
|
||||
|
||||
/// Changes the foreground color.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::style::{Color, Style};
|
||||
/// let s = Style::default().fg(Color::Red);
|
||||
/// assert_eq!(s.fg, Color::Red);
|
||||
/// ```
|
||||
pub const fn fg(mut self, color: Color) -> Style {
|
||||
self.fg = color;
|
||||
self
|
||||
}
|
||||
|
||||
/// Changes the background color.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::style::{Color, Style};
|
||||
/// let s = Style::default().bg(Color::Red);
|
||||
/// assert_eq!(s.bg, Color::Red);
|
||||
/// ```
|
||||
pub const fn bg(mut self, color: Color) -> Style {
|
||||
self.bg = color;
|
||||
self
|
||||
}
|
||||
|
||||
/// Changes the emphasis.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::style::{Modifier, Style};
|
||||
/// let s = Style::default().modifier(Modifier::BOLD | Modifier::ITALIC);
|
||||
/// assert_eq!(s.modifier, Modifier::BOLD | Modifier::ITALIC);
|
||||
/// ```
|
||||
pub const fn modifier(mut self, modifier: Modifier) -> Style {
|
||||
self.modifier = modifier;
|
||||
self
|
||||
}
|
||||
|
||||
/// Creates a new [`Style`] by applying the given diff to its properties.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::style::{Color, Modifier, Style, StyleDiff};
|
||||
/// let style = Style::default().fg(Color::Green).bg(Color::Black).modifier(Modifier::BOLD);
|
||||
///
|
||||
/// let diff = StyleDiff::default();
|
||||
/// let patched = style.patch(diff);
|
||||
/// assert_eq!(patched, style);
|
||||
///
|
||||
/// let diff = StyleDiff::default().fg(Color::Blue).add_modifier(Modifier::ITALIC);
|
||||
/// let patched = style.patch(diff);
|
||||
/// assert_eq!(
|
||||
/// patched,
|
||||
/// Style {
|
||||
/// fg: Color::Blue,
|
||||
/// bg: Color::Black,
|
||||
/// modifier: Modifier::BOLD | Modifier::ITALIC,
|
||||
/// }
|
||||
/// );
|
||||
/// ```
|
||||
pub fn patch(mut self, diff: StyleDiff) -> Style {
|
||||
if let Some(c) = diff.fg {
|
||||
self.fg = c;
|
||||
}
|
||||
if let Some(c) = diff.bg {
|
||||
self.bg = c;
|
||||
}
|
||||
if let Some(m) = diff.modifier {
|
||||
self.modifier = m;
|
||||
}
|
||||
self.modifier.insert(diff.add_modifier);
|
||||
self.modifier.remove(diff.sub_modifier);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
/// StyleDiff is a set of updates that can be applied to a [`Style`] to get a
|
||||
/// new one.
|
||||
#[derive(Debug, Clone, Copy, PartialEq)]
|
||||
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
||||
pub struct StyleDiff {
|
||||
fg: Option<Color>,
|
||||
bg: Option<Color>,
|
||||
modifier: Option<Modifier>,
|
||||
add_modifier: Modifier,
|
||||
sub_modifier: Modifier,
|
||||
}
|
||||
|
||||
impl Default for StyleDiff {
|
||||
fn default() -> StyleDiff {
|
||||
StyleDiff {
|
||||
fg: None,
|
||||
bg: None,
|
||||
modifier: None,
|
||||
add_modifier: Modifier::empty(),
|
||||
sub_modifier: Modifier::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Style> for StyleDiff {
|
||||
fn from(s: Style) -> StyleDiff {
|
||||
StyleDiff {
|
||||
fg: Some(s.fg),
|
||||
bg: Some(s.bg),
|
||||
modifier: Some(s.modifier),
|
||||
add_modifier: Modifier::empty(),
|
||||
sub_modifier: Modifier::empty(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StyleDiff {
|
||||
/// Changes the foreground color.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::style::{Color, Style, StyleDiff};
|
||||
/// let style = Style::default().fg(Color::Blue);
|
||||
/// let diff = StyleDiff::default().fg(Color::Red);
|
||||
/// let diff = Style::default().fg(Color::Red);
|
||||
/// assert_eq!(style.patch(diff), Style::default().fg(Color::Red));
|
||||
/// ```
|
||||
pub fn fg(mut self, color: Color) -> StyleDiff {
|
||||
pub fn fg(mut self, color: Color) -> Style {
|
||||
self.fg = Some(color);
|
||||
self
|
||||
}
|
||||
|
@ -253,48 +104,31 @@ impl StyleDiff {
|
|||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::style::{Color, Style, StyleDiff};
|
||||
/// # use tui::style::{Color, Style};
|
||||
/// let style = Style::default().bg(Color::Blue);
|
||||
/// let diff = StyleDiff::default().bg(Color::Red);
|
||||
/// let diff = Style::default().bg(Color::Red);
|
||||
/// assert_eq!(style.patch(diff), Style::default().bg(Color::Red));
|
||||
/// ```
|
||||
pub fn bg(mut self, color: Color) -> StyleDiff {
|
||||
pub fn bg(mut self, color: Color) -> Style {
|
||||
self.bg = Some(color);
|
||||
self
|
||||
}
|
||||
|
||||
/// Changes the text emphasis.
|
||||
///
|
||||
/// When applied, it replaces the `Style` modifier with the given value.
|
||||
/// When applied, it adds the given modifier to the `Style` modifiers.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::style::{Color, Modifier, Style, StyleDiff};
|
||||
/// let style = Style::default().modifier(Modifier::BOLD);
|
||||
/// let diff = StyleDiff::default().modifier(Modifier::ITALIC);
|
||||
/// assert_eq!(style.patch(diff), Style::default().modifier(Modifier::ITALIC));
|
||||
/// # use tui::style::{Color, Modifier, Style};
|
||||
/// let style = Style::default().add_modifier(Modifier::BOLD);
|
||||
/// let diff = Style::default().add_modifier(Modifier::ITALIC);
|
||||
/// let patched = style.patch(diff);
|
||||
/// assert_eq!(patched.add_modifier, Modifier::BOLD | Modifier::ITALIC);
|
||||
/// assert_eq!(patched.sub_modifier, Modifier::empty());
|
||||
/// ```
|
||||
pub fn modifier(mut self, modifier: Modifier) -> StyleDiff {
|
||||
self.add_modifier = Modifier::empty();
|
||||
self.sub_modifier = Modifier::empty();
|
||||
self.modifier = Some(modifier);
|
||||
self
|
||||
}
|
||||
|
||||
/// Changes the text emphasis.
|
||||
///
|
||||
/// When applied, it adds the given modifiers to the `Style` modifier.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::style::{Color, Modifier, Style, StyleDiff};
|
||||
/// let style = Style::default().modifier(Modifier::BOLD);
|
||||
/// let diff = StyleDiff::default().add_modifier(Modifier::ITALIC);
|
||||
/// assert_eq!(style.patch(diff), Style::default().modifier(Modifier::BOLD | Modifier::ITALIC));
|
||||
/// ```
|
||||
pub fn add_modifier(mut self, modifier: Modifier) -> StyleDiff {
|
||||
pub fn add_modifier(mut self, modifier: Modifier) -> Style {
|
||||
self.sub_modifier.remove(modifier);
|
||||
self.add_modifier.insert(modifier);
|
||||
self
|
||||
|
@ -302,51 +136,46 @@ impl StyleDiff {
|
|||
|
||||
/// Changes the text emphasis.
|
||||
///
|
||||
/// When applied, it removes the given modifiers from the `Style` modifier.
|
||||
/// When applied, it removes the given modifier from the `Style` modifiers.
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::style::{Color, Modifier, Style, StyleDiff};
|
||||
/// let style = Style::default().modifier(Modifier::BOLD | Modifier::ITALIC);
|
||||
/// let diff = StyleDiff::default().remove_modifier(Modifier::ITALIC);
|
||||
/// assert_eq!(style.patch(diff), Style::default().modifier(Modifier::BOLD));
|
||||
/// # use tui::style::{Color, Modifier, Style};
|
||||
/// let style = Style::default().add_modifier(Modifier::BOLD | Modifier::ITALIC);
|
||||
/// let diff = Style::default().remove_modifier(Modifier::ITALIC);
|
||||
/// let patched = style.patch(diff);
|
||||
/// assert_eq!(patched.add_modifier, Modifier::BOLD);
|
||||
/// assert_eq!(patched.sub_modifier, Modifier::ITALIC);
|
||||
/// ```
|
||||
pub fn remove_modifier(mut self, modifier: Modifier) -> StyleDiff {
|
||||
pub fn remove_modifier(mut self, modifier: Modifier) -> Style {
|
||||
self.add_modifier.remove(modifier);
|
||||
self.sub_modifier.insert(modifier);
|
||||
self
|
||||
}
|
||||
|
||||
/// Results in a combined style diff that is equivalent to applying the two individual diffs to
|
||||
/// Results in a combined style that is equivalent to applying the two individual styles to
|
||||
/// a style one after the other.
|
||||
///
|
||||
/// ## Examples
|
||||
/// ```
|
||||
/// # use tui::style::{Color, Modifier, Style, StyleDiff};
|
||||
/// let style_1 = StyleDiff::default().fg(Color::Yellow);
|
||||
/// let style_2 = StyleDiff::default().bg(Color::Red);
|
||||
/// # use tui::style::{Color, Modifier, Style};
|
||||
/// let style_1 = Style::default().fg(Color::Yellow);
|
||||
/// let style_2 = Style::default().bg(Color::Red);
|
||||
/// let combined = style_1.patch(style_2);
|
||||
/// assert_eq!(
|
||||
/// Style::default().patch(style_1).patch(style_2),
|
||||
/// Style::default().patch(combined));
|
||||
/// ```
|
||||
pub fn patch(mut self, other: StyleDiff) -> StyleDiff {
|
||||
pub fn patch(mut self, other: Style) -> Style {
|
||||
self.fg = other.fg.or(self.fg);
|
||||
self.bg = other.bg.or(self.bg);
|
||||
self.modifier = other.modifier.or(self.modifier);
|
||||
|
||||
// If the other is about to specify a full modifier, it would fully override whatever
|
||||
// add/sub modifiers the current style wants to apply so ignore those in that case.
|
||||
if other.modifier.is_some() {
|
||||
self.add_modifier = other.add_modifier;
|
||||
self.sub_modifier = other.sub_modifier;
|
||||
} else {
|
||||
self.add_modifier.remove(other.sub_modifier);
|
||||
self.add_modifier.insert(other.add_modifier);
|
||||
self.sub_modifier.remove(other.add_modifier);
|
||||
self.sub_modifier.insert(other.sub_modifier);
|
||||
}
|
||||
self.add_modifier.remove(other.sub_modifier);
|
||||
self.add_modifier.insert(other.add_modifier);
|
||||
self.sub_modifier.remove(other.add_modifier);
|
||||
self.sub_modifier.insert(other.sub_modifier);
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -355,30 +184,27 @@ impl StyleDiff {
|
|||
mod tests {
|
||||
use super::*;
|
||||
|
||||
fn diffs() -> Vec<StyleDiff> {
|
||||
fn styles() -> Vec<Style> {
|
||||
vec![
|
||||
StyleDiff::default(),
|
||||
StyleDiff::default().fg(Color::Yellow),
|
||||
StyleDiff::default().bg(Color::Yellow),
|
||||
StyleDiff::default().modifier(Modifier::BOLD),
|
||||
StyleDiff::default().modifier(Modifier::ITALIC),
|
||||
StyleDiff::default().modifier(Modifier::ITALIC | Modifier::BOLD),
|
||||
StyleDiff::default().add_modifier(Modifier::BOLD),
|
||||
StyleDiff::default().remove_modifier(Modifier::BOLD),
|
||||
StyleDiff::default().add_modifier(Modifier::ITALIC),
|
||||
StyleDiff::default().remove_modifier(Modifier::ITALIC),
|
||||
StyleDiff::default().add_modifier(Modifier::ITALIC | Modifier::BOLD),
|
||||
StyleDiff::default().remove_modifier(Modifier::ITALIC | Modifier::BOLD),
|
||||
Style::default(),
|
||||
Style::default().fg(Color::Yellow),
|
||||
Style::default().bg(Color::Yellow),
|
||||
Style::default().add_modifier(Modifier::BOLD),
|
||||
Style::default().remove_modifier(Modifier::BOLD),
|
||||
Style::default().add_modifier(Modifier::ITALIC),
|
||||
Style::default().remove_modifier(Modifier::ITALIC),
|
||||
Style::default().add_modifier(Modifier::ITALIC | Modifier::BOLD),
|
||||
Style::default().remove_modifier(Modifier::ITALIC | Modifier::BOLD),
|
||||
]
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn combined_patch_gives_same_result_as_individual_patch() {
|
||||
let diffs = diffs();
|
||||
for &a in &diffs {
|
||||
for &b in &diffs {
|
||||
for &c in &diffs {
|
||||
for &d in &diffs {
|
||||
let styles = styles();
|
||||
for &a in &styles {
|
||||
for &b in &styles {
|
||||
for &c in &styles {
|
||||
for &d in &styles {
|
||||
let combined = a.patch(b.patch(c.patch(d)));
|
||||
|
||||
assert_eq!(
|
||||
|
@ -390,29 +216,4 @@ mod tests {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn diffs_respect_later_modifiers() {
|
||||
let diffs = diffs();
|
||||
for &a in &diffs {
|
||||
for &b in &diffs {
|
||||
let random_diff = a.patch(b);
|
||||
|
||||
let set_bold = random_diff.modifier(Modifier::BOLD);
|
||||
assert_eq!(Style::default().patch(set_bold).modifier, Modifier::BOLD);
|
||||
|
||||
let add_bold = random_diff.add_modifier(Modifier::BOLD);
|
||||
assert!(Style::default()
|
||||
.patch(add_bold)
|
||||
.modifier
|
||||
.contains(Modifier::BOLD));
|
||||
|
||||
let remove_bold = random_diff.remove_modifier(Modifier::BOLD);
|
||||
assert!(!Style::default()
|
||||
.patch(remove_bold)
|
||||
.modifier
|
||||
.contains(Modifier::BOLD));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
90
src/text.rs
90
src/text.rs
|
@ -21,32 +21,32 @@
|
|||
//! ```rust
|
||||
//! # use tui::widgets::Block;
|
||||
//! # use tui::text::{Span, Spans};
|
||||
//! # use tui::style::{Color, StyleDiff};
|
||||
//! # use tui::style::{Color, Style};
|
||||
//! // A simple string with no styling.
|
||||
//! // Converted to Spans(vec![
|
||||
//! // Span { content: Cow::Borrowed("My title"), style_diff: StyleDiff { .. } }
|
||||
//! // Span { content: Cow::Borrowed("My title"), style: Style { .. } }
|
||||
//! // ])
|
||||
//! let block = Block::default().title("My title");
|
||||
//!
|
||||
//! // A simple string with a unique style.
|
||||
//! // Converted to Spans(vec![
|
||||
//! // Span { content: Cow::Borrowed("My title"), style_diff: StyleDiff { fg: Some(Color::Yellow), .. }
|
||||
//! // Span { content: Cow::Borrowed("My title"), style: Style { fg: Some(Color::Yellow), .. }
|
||||
//! // ])
|
||||
//! let block = Block::default().title(
|
||||
//! Span::styled("My title", StyleDiff::default().fg(Color::Yellow))
|
||||
//! Span::styled("My title", Style::default().fg(Color::Yellow))
|
||||
//! );
|
||||
//!
|
||||
//! // A string with multiple styles.
|
||||
//! // Converted to Spans(vec![
|
||||
//! // Span { content: Cow::Borrowed("My"), style_diff: StyleDiff { fg: Some(Color::Yellow), .. } },
|
||||
//! // Span { content: Cow::Borrowed("My"), style: Style { fg: Some(Color::Yellow), .. } },
|
||||
//! // Span { content: Cow::Borrowed(" title"), .. }
|
||||
//! // ])
|
||||
//! let block = Block::default().title(vec![
|
||||
//! Span::styled("My", StyleDiff::default().fg(Color::Yellow)),
|
||||
//! Span::styled("My", Style::default().fg(Color::Yellow)),
|
||||
//! Span::raw(" title"),
|
||||
//! ]);
|
||||
//! ```
|
||||
use crate::style::{Style, StyleDiff};
|
||||
use crate::style::Style;
|
||||
use std::{borrow::Cow, cmp::max};
|
||||
use unicode_segmentation::UnicodeSegmentation;
|
||||
use unicode_width::UnicodeWidthStr;
|
||||
|
@ -62,7 +62,7 @@ pub struct StyledGrapheme<'a> {
|
|||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Span<'a> {
|
||||
pub content: Cow<'a, str>,
|
||||
pub style_diff: StyleDiff,
|
||||
pub style: Style,
|
||||
}
|
||||
|
||||
impl<'a> Span<'a> {
|
||||
|
@ -81,7 +81,7 @@ impl<'a> Span<'a> {
|
|||
{
|
||||
Span {
|
||||
content: content.into(),
|
||||
style_diff: StyleDiff::default(),
|
||||
style: Style::default(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -91,18 +91,18 @@ impl<'a> Span<'a> {
|
|||
///
|
||||
/// ```rust
|
||||
/// # use tui::text::Span;
|
||||
/// # use tui::style::{Color, Modifier, StyleDiff};
|
||||
/// let style = StyleDiff::default().fg(Color::Yellow).add_modifier(Modifier::ITALIC);
|
||||
/// # use tui::style::{Color, Modifier, Style};
|
||||
/// let style = Style::default().fg(Color::Yellow).add_modifier(Modifier::ITALIC);
|
||||
/// Span::styled("My text", style);
|
||||
/// Span::styled(String::from("My text"), style);
|
||||
/// ```
|
||||
pub fn styled<T>(content: T, style_diff: StyleDiff) -> Span<'a>
|
||||
pub fn styled<T>(content: T, style: Style) -> Span<'a>
|
||||
where
|
||||
T: Into<Cow<'a, str>>,
|
||||
{
|
||||
Span {
|
||||
content: content.into(),
|
||||
style_diff,
|
||||
style,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -113,17 +113,17 @@ impl<'a> Span<'a> {
|
|||
|
||||
/// Returns an iterator over the graphemes held by this span.
|
||||
///
|
||||
/// `base_style` is the [`Style`] that will be patched with each grapheme [`StyleDiff`] to get
|
||||
/// `base_style` is the [`Style`] that will be patched with each grapheme [`Style`] to get
|
||||
/// the resulting [`Style`].
|
||||
///
|
||||
/// ## Examples
|
||||
///
|
||||
/// ```rust
|
||||
/// # use tui::text::{Span, StyledGrapheme};
|
||||
/// # use tui::style::{Color, Modifier, Style, StyleDiff};
|
||||
/// # use tui::style::{Color, Modifier, Style};
|
||||
/// # use std::iter::Iterator;
|
||||
/// let style_diff = StyleDiff::default().fg(Color::Yellow);
|
||||
/// let span = Span::styled("Text", style_diff);
|
||||
/// let style = Style::default().fg(Color::Yellow);
|
||||
/// let span = Span::styled("Text", style);
|
||||
/// let style = Style::default().fg(Color::Green).bg(Color::Black);
|
||||
/// let styled_graphemes = span.styled_graphemes(style);
|
||||
/// assert_eq!(
|
||||
|
@ -131,33 +131,37 @@ impl<'a> Span<'a> {
|
|||
/// StyledGrapheme {
|
||||
/// symbol: "T",
|
||||
/// style: Style {
|
||||
/// fg: Color::Yellow,
|
||||
/// bg: Color::Black,
|
||||
/// modifier: Modifier::empty(),
|
||||
/// fg: Some(Color::Yellow),
|
||||
/// bg: Some(Color::Black),
|
||||
/// add_modifier: Modifier::empty(),
|
||||
/// sub_modifier: Modifier::empty(),
|
||||
/// },
|
||||
/// },
|
||||
/// StyledGrapheme {
|
||||
/// symbol: "e",
|
||||
/// style: Style {
|
||||
/// fg: Color::Yellow,
|
||||
/// bg: Color::Black,
|
||||
/// modifier: Modifier::empty(),
|
||||
/// fg: Some(Color::Yellow),
|
||||
/// bg: Some(Color::Black),
|
||||
/// add_modifier: Modifier::empty(),
|
||||
/// sub_modifier: Modifier::empty(),
|
||||
/// },
|
||||
/// },
|
||||
/// StyledGrapheme {
|
||||
/// symbol: "x",
|
||||
/// style: Style {
|
||||
/// fg: Color::Yellow,
|
||||
/// bg: Color::Black,
|
||||
/// modifier: Modifier::empty(),
|
||||
/// fg: Some(Color::Yellow),
|
||||
/// bg: Some(Color::Black),
|
||||
/// add_modifier: Modifier::empty(),
|
||||
/// sub_modifier: Modifier::empty(),
|
||||
/// },
|
||||
/// },
|
||||
/// StyledGrapheme {
|
||||
/// symbol: "t",
|
||||
/// style: Style {
|
||||
/// fg: Color::Yellow,
|
||||
/// bg: Color::Black,
|
||||
/// modifier: Modifier::empty(),
|
||||
/// fg: Some(Color::Yellow),
|
||||
/// bg: Some(Color::Black),
|
||||
/// add_modifier: Modifier::empty(),
|
||||
/// sub_modifier: Modifier::empty(),
|
||||
/// },
|
||||
/// },
|
||||
/// ],
|
||||
|
@ -171,7 +175,7 @@ impl<'a> Span<'a> {
|
|||
UnicodeSegmentation::graphemes(self.content.as_ref(), true)
|
||||
.map(move |g| StyledGrapheme {
|
||||
symbol: g,
|
||||
style: base_style.patch(self.style_diff),
|
||||
style: base_style.patch(self.style),
|
||||
})
|
||||
.filter(|s| s.symbol != "\n")
|
||||
}
|
||||
|
@ -206,9 +210,9 @@ impl<'a> Spans<'a> {
|
|||
///
|
||||
/// ```rust
|
||||
/// # use tui::text::{Span, Spans};
|
||||
/// # use tui::style::{Color, StyleDiff};
|
||||
/// # use tui::style::{Color, Style};
|
||||
/// let spans = Spans::from(vec![
|
||||
/// Span::styled("My", StyleDiff::default().fg(Color::Yellow)),
|
||||
/// Span::styled("My", Style::default().fg(Color::Yellow)),
|
||||
/// Span::raw(" text"),
|
||||
/// ]);
|
||||
/// assert_eq!(7, spans.width());
|
||||
|
@ -290,6 +294,14 @@ impl<'a> Text<'a> {
|
|||
pub fn height(&self) -> usize {
|
||||
self.lines.len()
|
||||
}
|
||||
|
||||
pub fn patch_style(&mut self, style: Style) {
|
||||
for line in &mut self.lines {
|
||||
for span in &mut line.0 {
|
||||
span.style = span.style.patch(style);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a str> for Text<'a> {
|
||||
|
@ -300,6 +312,20 @@ impl<'a> From<&'a str> for Text<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Span<'a>> for Text<'a> {
|
||||
fn from(span: Span<'a>) -> Text<'a> {
|
||||
Text {
|
||||
lines: vec![Spans::from(span)],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Spans<'a>> for Text<'a> {
|
||||
fn from(spans: Spans<'a>) -> Text<'a> {
|
||||
Text { lines: vec![spans] }
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<Vec<Spans<'a>>> for Text<'a> {
|
||||
fn from(lines: Vec<Spans<'a>>) -> Text<'a> {
|
||||
Text { lines }
|
||||
|
|
|
@ -19,8 +19,8 @@ use unicode_width::UnicodeWidthStr;
|
|||
/// .block(Block::default().title("BarChart").borders(Borders::ALL))
|
||||
/// .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))
|
||||
/// .bar_style(Style::default().fg(Color::Yellow).bg(Color::Red))
|
||||
/// .value_style(Style::default().fg(Color::Red).add_modifier(Modifier::BOLD))
|
||||
/// .label_style(Style::default().fg(Color::White))
|
||||
/// .data(&[("B0", 0), ("B1", 2), ("B2", 4), ("B3", 3)])
|
||||
/// .max(4);
|
||||
|
@ -35,6 +35,8 @@ pub struct BarChart<'a> {
|
|||
bar_gap: u16,
|
||||
/// Set of symbols used to display the data
|
||||
bar_set: symbols::bar::Set,
|
||||
/// Style of the bars
|
||||
bar_style: Style,
|
||||
/// Style of the values printed at the bottom of each bar
|
||||
value_style: Style,
|
||||
/// Style of the labels printed under each bar
|
||||
|
@ -57,6 +59,7 @@ impl<'a> Default for BarChart<'a> {
|
|||
max: None,
|
||||
data: &[],
|
||||
values: Vec::new(),
|
||||
bar_style: Style::default(),
|
||||
bar_width: 1,
|
||||
bar_gap: 1,
|
||||
bar_set: symbols::bar::NINE_LEVELS,
|
||||
|
@ -87,6 +90,11 @@ impl<'a> BarChart<'a> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn bar_style(mut self, style: Style) -> BarChart<'a> {
|
||||
self.bar_style = style;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn bar_width(mut self, width: u16) -> BarChart<'a> {
|
||||
self.bar_width = width;
|
||||
self
|
||||
|
@ -120,6 +128,8 @@ impl<'a> BarChart<'a> {
|
|||
|
||||
impl<'a> Widget for BarChart<'a> {
|
||||
fn render(mut self, area: Rect, buf: &mut Buffer) {
|
||||
buf.set_style(area, self.style);
|
||||
|
||||
let chart_area = match self.block.take() {
|
||||
Some(b) => {
|
||||
let inner_area = b.inner(area);
|
||||
|
@ -133,8 +143,6 @@ impl<'a> Widget for BarChart<'a> {
|
|||
return;
|
||||
}
|
||||
|
||||
buf.set_background(chart_area, self.style.bg);
|
||||
|
||||
let max = self
|
||||
.max
|
||||
.unwrap_or_else(|| self.data.iter().fold(0, |acc, &(_, v)| max(v, acc)));
|
||||
|
@ -173,7 +181,7 @@ impl<'a> Widget for BarChart<'a> {
|
|||
chart_area.top() + j,
|
||||
)
|
||||
.set_symbol(symbol)
|
||||
.set_style(self.style);
|
||||
.set_style(self.bar_style);
|
||||
}
|
||||
|
||||
if d.1 > 8 {
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
buffer::Buffer,
|
||||
layout::Rect,
|
||||
style::{Style, StyleDiff},
|
||||
style::Style,
|
||||
symbols::line,
|
||||
text::{Span, Spans},
|
||||
widgets::{Borders, Widget},
|
||||
|
@ -84,7 +84,7 @@ impl<'a> Block<'a> {
|
|||
pub fn title_style(mut self, style: Style) -> Block<'a> {
|
||||
if let Some(t) = self.title {
|
||||
let title = String::from(t);
|
||||
self.title = Some(Spans::from(Span::styled(title, StyleDiff::from(style))));
|
||||
self.title = Some(Spans::from(Span::styled(title, style)));
|
||||
}
|
||||
self
|
||||
}
|
||||
|
@ -135,12 +135,12 @@ impl<'a> Block<'a> {
|
|||
|
||||
impl<'a> Widget for Block<'a> {
|
||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||
buf.set_style(area, self.style);
|
||||
|
||||
if area.width < 2 || area.height < 2 {
|
||||
return;
|
||||
}
|
||||
|
||||
buf.set_background(area, self.style.bg);
|
||||
|
||||
let symbols = BorderType::line_symbols(self.border_type);
|
||||
// Sides
|
||||
if self.borders.intersects(Borders::LEFT) {
|
||||
|
@ -208,7 +208,7 @@ impl<'a> Widget for Block<'a> {
|
|||
0
|
||||
};
|
||||
let width = area.width - lx - rx;
|
||||
buf.set_spans(area.left() + lx, area.top(), &title, width, self.style);
|
||||
buf.set_spans(area.left() + lx, area.top(), &title, width);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
buffer::Buffer,
|
||||
layout::{Constraint, Rect},
|
||||
style::{Style, StyleDiff},
|
||||
style::{Color, Style},
|
||||
symbols,
|
||||
text::{Span, Spans},
|
||||
widgets::{
|
||||
|
@ -52,7 +52,7 @@ impl<'a> Axis<'a> {
|
|||
pub fn title_style(mut self, style: Style) -> Axis<'a> {
|
||||
if let Some(t) = self.title {
|
||||
let title = String::from(t);
|
||||
self.title = Some(Spans::from(Span::styled(title, StyleDiff::from(style))));
|
||||
self.title = Some(Spans::from(Span::styled(title, style)));
|
||||
}
|
||||
self
|
||||
}
|
||||
|
@ -183,7 +183,7 @@ impl Default for ChartLayout {
|
|||
/// ```
|
||||
/// # use tui::symbols;
|
||||
/// # use tui::widgets::{Block, Borders, Chart, Axis, Dataset, GraphType};
|
||||
/// # use tui::style::{Style, StyleDiff, Color};
|
||||
/// # use tui::style::{Style, Color};
|
||||
/// # use tui::text::Span;
|
||||
/// let datasets = vec![
|
||||
/// Dataset::default()
|
||||
|
@ -202,12 +202,12 @@ impl Default for ChartLayout {
|
|||
/// Chart::new(datasets)
|
||||
/// .block(Block::default().title("Chart"))
|
||||
/// .x_axis(Axis::default()
|
||||
/// .title(Span::styled("X Axis", StyleDiff::default().fg(Color::Red)))
|
||||
/// .title(Span::styled("X Axis", Style::default().fg(Color::Red)))
|
||||
/// .style(Style::default().fg(Color::White))
|
||||
/// .bounds([0.0, 10.0])
|
||||
/// .labels(["0.0", "5.0", "10.0"].iter().cloned().map(Span::from).collect()))
|
||||
/// .y_axis(Axis::default()
|
||||
/// .title(Span::styled("Y Axis", StyleDiff::default().fg(Color::Red)))
|
||||
/// .title(Span::styled("Y Axis", Style::default().fg(Color::Red)))
|
||||
/// .style(Style::default().fg(Color::White))
|
||||
/// .bounds([0.0, 10.0])
|
||||
/// .labels(["0.0", "5.0", "10.0"].iter().cloned().map(Span::from).collect()));
|
||||
|
@ -369,6 +369,7 @@ impl<'a> Chart<'a> {
|
|||
|
||||
impl<'a> Widget for Chart<'a> {
|
||||
fn render(mut self, area: Rect, buf: &mut Buffer) {
|
||||
buf.set_style(area, self.style);
|
||||
let chart_area = match self.block.take() {
|
||||
Some(b) => {
|
||||
let inner_area = b.inner(area);
|
||||
|
@ -384,28 +385,14 @@ impl<'a> Widget for Chart<'a> {
|
|||
return;
|
||||
}
|
||||
|
||||
buf.set_background(chart_area, self.style.bg);
|
||||
|
||||
if let Some((x, y)) = layout.title_x {
|
||||
let title = self.x_axis.title.unwrap();
|
||||
buf.set_spans(
|
||||
x,
|
||||
y,
|
||||
&title,
|
||||
graph_area.right().saturating_sub(x),
|
||||
self.style,
|
||||
);
|
||||
buf.set_spans(x, y, &title, graph_area.right().saturating_sub(x));
|
||||
}
|
||||
|
||||
if let Some((x, y)) = layout.title_y {
|
||||
let title = self.y_axis.title.unwrap();
|
||||
buf.set_spans(
|
||||
x,
|
||||
y,
|
||||
&title,
|
||||
graph_area.right().saturating_sub(x),
|
||||
self.style,
|
||||
);
|
||||
buf.set_spans(x, y, &title, graph_area.right().saturating_sub(x));
|
||||
}
|
||||
|
||||
if let Some(y) = layout.label_x {
|
||||
|
@ -420,7 +407,6 @@ impl<'a> Widget for Chart<'a> {
|
|||
y,
|
||||
label,
|
||||
label.width() as u16,
|
||||
self.style,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -432,13 +418,7 @@ impl<'a> Widget for Chart<'a> {
|
|||
for (i, label) in labels.iter().enumerate() {
|
||||
let dy = i as u16 * (graph_area.height - 1) / (labels_len - 1);
|
||||
if dy < graph_area.bottom() {
|
||||
buf.set_span(
|
||||
x,
|
||||
graph_area.bottom() - 1 - dy,
|
||||
label,
|
||||
label.width() as u16,
|
||||
self.style,
|
||||
);
|
||||
buf.set_span(x, graph_area.bottom() - 1 - dy, label, label.width() as u16);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -469,14 +449,14 @@ impl<'a> Widget for Chart<'a> {
|
|||
|
||||
for dataset in &self.datasets {
|
||||
Canvas::default()
|
||||
.background_color(self.style.bg)
|
||||
.background_color(self.style.bg.unwrap_or(Color::Reset))
|
||||
.x_bounds(self.x_axis.bounds)
|
||||
.y_bounds(self.y_axis.bounds)
|
||||
.marker(dataset.marker)
|
||||
.paint(|ctx| {
|
||||
ctx.draw(&Points {
|
||||
coords: dataset.data,
|
||||
color: dataset.style.fg,
|
||||
color: dataset.style.fg.unwrap_or(Color::Reset),
|
||||
});
|
||||
if let GraphType::Line = dataset.graph_type {
|
||||
for data in dataset.data.windows(2) {
|
||||
|
@ -485,7 +465,7 @@ impl<'a> Widget for Chart<'a> {
|
|||
y1: data[0].1,
|
||||
x2: data[1].0,
|
||||
y2: data[1].1,
|
||||
color: dataset.style.fg,
|
||||
color: dataset.style.fg.unwrap_or(Color::Reset),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -15,7 +15,7 @@ use crate::{
|
|||
/// # use tui::style::{Style, Color, Modifier};
|
||||
/// Gauge::default()
|
||||
/// .block(Block::default().borders(Borders::ALL).title("Progress"))
|
||||
/// .style(Style::default().fg(Color::White).bg(Color::Black).modifier(Modifier::ITALIC))
|
||||
/// .gauge_style(Style::default().fg(Color::White).bg(Color::Black).add_modifier(Modifier::ITALIC))
|
||||
/// .percent(20);
|
||||
/// ```
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -24,6 +24,7 @@ pub struct Gauge<'a> {
|
|||
ratio: f64,
|
||||
label: Option<Span<'a>>,
|
||||
style: Style,
|
||||
gauge_style: Style,
|
||||
}
|
||||
|
||||
impl<'a> Default for Gauge<'a> {
|
||||
|
@ -32,7 +33,8 @@ impl<'a> Default for Gauge<'a> {
|
|||
block: None,
|
||||
ratio: 0.0,
|
||||
label: None,
|
||||
style: Default::default(),
|
||||
style: Style::default(),
|
||||
gauge_style: Style::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -74,10 +76,16 @@ impl<'a> Gauge<'a> {
|
|||
self.style = style;
|
||||
self
|
||||
}
|
||||
|
||||
pub fn gauge_style(mut self, style: Style) -> Gauge<'a> {
|
||||
self.gauge_style = style;
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Widget for Gauge<'a> {
|
||||
fn render(mut self, area: Rect, buf: &mut Buffer) {
|
||||
buf.set_style(area, self.style);
|
||||
let gauge_area = match self.block.take() {
|
||||
Some(b) => {
|
||||
let inner_area = b.inner(area);
|
||||
|
@ -86,14 +94,11 @@ impl<'a> Widget for Gauge<'a> {
|
|||
}
|
||||
None => area,
|
||||
};
|
||||
buf.set_style(gauge_area, self.gauge_style);
|
||||
if gauge_area.height < 1 {
|
||||
return;
|
||||
}
|
||||
|
||||
if self.style.bg != Color::Reset {
|
||||
buf.set_background(gauge_area, self.style.bg);
|
||||
}
|
||||
|
||||
let center = gauge_area.height / 2 + gauge_area.top();
|
||||
let width = (f64::from(gauge_area.width) * self.ratio).round() as u16;
|
||||
let end = gauge_area.left() + width;
|
||||
|
@ -111,14 +116,14 @@ impl<'a> Widget for Gauge<'a> {
|
|||
if y == center {
|
||||
let label_width = label.width() as u16;
|
||||
let middle = (gauge_area.width - label_width) / 2 + gauge_area.left();
|
||||
buf.set_span(middle, y, &label, gauge_area.right() - middle, self.style);
|
||||
buf.set_span(middle, y, &label, gauge_area.right() - middle);
|
||||
}
|
||||
|
||||
// Fix colors
|
||||
for x in gauge_area.left()..end {
|
||||
buf.get_mut(x, y)
|
||||
.set_fg(self.style.bg)
|
||||
.set_bg(self.style.fg);
|
||||
.set_fg(self.gauge_style.bg.unwrap_or(Color::Reset))
|
||||
.set_bg(self.gauge_style.fg.unwrap_or(Color::Reset));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
buffer::Buffer,
|
||||
layout::{Corner, Rect},
|
||||
style::{Style, StyleDiff},
|
||||
style::Style,
|
||||
text::Text,
|
||||
widgets::{Block, StatefulWidget, Widget},
|
||||
};
|
||||
|
@ -39,7 +39,7 @@ impl ListState {
|
|||
#[derive(Debug, Clone)]
|
||||
pub struct ListItem<'a> {
|
||||
content: Text<'a>,
|
||||
style_diff: StyleDiff,
|
||||
style: Style,
|
||||
}
|
||||
|
||||
impl<'a> ListItem<'a> {
|
||||
|
@ -49,12 +49,12 @@ impl<'a> ListItem<'a> {
|
|||
{
|
||||
ListItem {
|
||||
content: content.into(),
|
||||
style_diff: StyleDiff::default(),
|
||||
style: Style::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn style_diff(mut self, style_diff: StyleDiff) -> ListItem<'a> {
|
||||
self.style_diff = style_diff;
|
||||
pub fn style(mut self, style: Style) -> ListItem<'a> {
|
||||
self.style = style;
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -69,12 +69,12 @@ impl<'a> ListItem<'a> {
|
|||
///
|
||||
/// ```
|
||||
/// # use tui::widgets::{Block, Borders, List, ListItem};
|
||||
/// # use tui::style::{Style, StyleDiff, Color, Modifier};
|
||||
/// # use tui::style::{Style, Color, Modifier};
|
||||
/// let items = [ListItem::new("Item 1"), ListItem::new("Item 2"), ListItem::new("Item 3")];
|
||||
/// List::new(items)
|
||||
/// .block(Block::default().title("List").borders(Borders::ALL))
|
||||
/// .style(Style::default().fg(Color::White))
|
||||
/// .highlight_style_diff(StyleDiff::default().modifier(Modifier::ITALIC))
|
||||
/// .highlight_style(Style::default().add_modifier(Modifier::ITALIC))
|
||||
/// .highlight_symbol(">>");
|
||||
/// ```
|
||||
#[derive(Debug, Clone)]
|
||||
|
@ -85,7 +85,7 @@ pub struct List<'a> {
|
|||
style: Style,
|
||||
start_corner: Corner,
|
||||
/// Style used to render selected item
|
||||
highlight_style_diff: StyleDiff,
|
||||
highlight_style: Style,
|
||||
/// Symbol in front of the selected item (Shift all items to the right)
|
||||
highlight_symbol: Option<&'a str>,
|
||||
}
|
||||
|
@ -100,7 +100,7 @@ impl<'a> List<'a> {
|
|||
style: Style::default(),
|
||||
items: items.into(),
|
||||
start_corner: Corner::TopLeft,
|
||||
highlight_style_diff: StyleDiff::default(),
|
||||
highlight_style: Style::default(),
|
||||
highlight_symbol: None,
|
||||
}
|
||||
}
|
||||
|
@ -120,8 +120,8 @@ impl<'a> List<'a> {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn highlight_style_diff(mut self, diff: StyleDiff) -> List<'a> {
|
||||
self.highlight_style_diff = diff;
|
||||
pub fn highlight_style(mut self, style: Style) -> List<'a> {
|
||||
self.highlight_style = style;
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -135,6 +135,7 @@ impl<'a> StatefulWidget for List<'a> {
|
|||
type State = ListState;
|
||||
|
||||
fn render(mut self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
|
||||
buf.set_style(area, self.style);
|
||||
let list_area = match self.block.take() {
|
||||
Some(b) => {
|
||||
let inner_area = b.inner(area);
|
||||
|
@ -148,8 +149,6 @@ impl<'a> StatefulWidget for List<'a> {
|
|||
return;
|
||||
}
|
||||
|
||||
buf.set_background(list_area, self.style.bg);
|
||||
|
||||
if self.items.is_empty() {
|
||||
return;
|
||||
}
|
||||
|
@ -191,6 +190,7 @@ impl<'a> StatefulWidget for List<'a> {
|
|||
.collect::<String>();
|
||||
|
||||
let mut current_height = 0;
|
||||
let has_selection = state.selected.is_some();
|
||||
for (i, item) in self
|
||||
.items
|
||||
.iter_mut()
|
||||
|
@ -215,40 +215,27 @@ impl<'a> StatefulWidget for List<'a> {
|
|||
width: list_area.width,
|
||||
height: item.height() as u16,
|
||||
};
|
||||
let item_style = self.style.patch(item.style_diff);
|
||||
buf.set_background(area, item_style.bg);
|
||||
let elem_x = if let Some(s) = state.selected {
|
||||
if s == i {
|
||||
for line in &mut item.content.lines {
|
||||
for span in &mut line.0 {
|
||||
span.style_diff = span.style_diff.patch(self.highlight_style_diff);
|
||||
}
|
||||
}
|
||||
let (x, _) = buf.set_stringn(
|
||||
x,
|
||||
y,
|
||||
highlight_symbol,
|
||||
list_area.width as usize,
|
||||
item_style.patch(self.highlight_style_diff),
|
||||
);
|
||||
x
|
||||
let item_style = self.style.patch(item.style);
|
||||
buf.set_style(area, item_style);
|
||||
|
||||
let is_selected = state.selected.map(|s| s == i).unwrap_or(false);
|
||||
let elem_x = if has_selection {
|
||||
let symbol = if is_selected {
|
||||
highlight_symbol
|
||||
} else {
|
||||
let (x, _) =
|
||||
buf.set_stringn(x, y, &blank_symbol, list_area.width as usize, item_style);
|
||||
x
|
||||
}
|
||||
&blank_symbol
|
||||
};
|
||||
let (x, _) = buf.set_stringn(x, y, symbol, list_area.width as usize, item_style);
|
||||
x
|
||||
} else {
|
||||
x
|
||||
};
|
||||
let max_element_width = (list_area.width - (elem_x - x)) as usize;
|
||||
for (j, line) in item.content.lines.iter().enumerate() {
|
||||
buf.set_spans(
|
||||
elem_x,
|
||||
y + j as u16,
|
||||
line,
|
||||
max_element_width as u16,
|
||||
self.style,
|
||||
);
|
||||
buf.set_spans(elem_x, y + j as u16, line, max_element_width as u16);
|
||||
}
|
||||
if is_selected {
|
||||
buf.set_style(area, self.highlight_style);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -26,15 +26,15 @@ fn get_line_offset(line_width: u16, text_area_width: u16, alignment: Alignment)
|
|||
/// ```
|
||||
/// # use tui::text::{Text, Spans, Span};
|
||||
/// # use tui::widgets::{Block, Borders, Paragraph, Wrap};
|
||||
/// # use tui::style::{Style, StyleDiff, Color, Modifier};
|
||||
/// # use tui::style::{Style, Color, Modifier};
|
||||
/// # use tui::layout::{Alignment};
|
||||
/// let text = vec![
|
||||
/// Spans::from(vec![
|
||||
/// Span::raw("First"),
|
||||
/// Span::styled("line",StyleDiff::default().add_modifier(Modifier::ITALIC)),
|
||||
/// Span::styled("line",Style::default().add_modifier(Modifier::ITALIC)),
|
||||
/// Span::raw("."),
|
||||
/// ]),
|
||||
/// Spans::from(Span::styled("Second line", StyleDiff::default().fg(Color::Red))),
|
||||
/// Spans::from(Span::styled("Second line", Style::default().fg(Color::Red))),
|
||||
/// ];
|
||||
/// Paragraph::new(text)
|
||||
/// .block(Block::default().title("Paragraph").borders(Borders::ALL))
|
||||
|
@ -134,6 +134,7 @@ impl<'a> Paragraph<'a> {
|
|||
|
||||
impl<'a> Widget for Paragraph<'a> {
|
||||
fn render(mut self, area: Rect, buf: &mut Buffer) {
|
||||
buf.set_style(area, self.style);
|
||||
let text_area = match self.block.take() {
|
||||
Some(b) => {
|
||||
let inner_area = b.inner(area);
|
||||
|
@ -147,8 +148,6 @@ impl<'a> Widget for Paragraph<'a> {
|
|||
return;
|
||||
}
|
||||
|
||||
buf.set_background(text_area, self.style.bg);
|
||||
|
||||
let style = self.style;
|
||||
let mut styled = self.text.lines.iter().flat_map(|spans| {
|
||||
spans
|
||||
|
|
|
@ -121,8 +121,7 @@ impl<'a> Widget for Sparkline<'a> {
|
|||
};
|
||||
buf.get_mut(spark_area.left() + i as u16, spark_area.top() + j)
|
||||
.set_symbol(symbol)
|
||||
.set_fg(self.style.fg)
|
||||
.set_bg(self.style.bg);
|
||||
.set_style(self.style);
|
||||
|
||||
if *d > 8 {
|
||||
*d -= 8;
|
||||
|
|
|
@ -220,6 +220,8 @@ where
|
|||
type State = TableState;
|
||||
|
||||
fn render(mut self, area: Rect, buf: &mut Buffer, state: &mut Self::State) {
|
||||
buf.set_style(area, self.style);
|
||||
|
||||
// Render block if necessary and get the drawing area
|
||||
let table_area = match self.block.take() {
|
||||
Some(b) => {
|
||||
|
@ -230,8 +232,6 @@ where
|
|||
None => area,
|
||||
};
|
||||
|
||||
buf.set_background(table_area, self.style.bg);
|
||||
|
||||
let mut solver = Solver::new();
|
||||
let mut var_indices = HashMap::new();
|
||||
let mut ccs = Vec::new();
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
buffer::Buffer,
|
||||
layout::Rect,
|
||||
style::{Style, StyleDiff},
|
||||
style::Style,
|
||||
symbols,
|
||||
text::{Span, Spans},
|
||||
widgets::{Block, Widget},
|
||||
|
@ -33,8 +33,8 @@ pub struct Tabs<'a> {
|
|||
selected: usize,
|
||||
/// The style used to draw the text
|
||||
style: Style,
|
||||
/// Style diff to apply to the selected item
|
||||
highlight_style_diff: StyleDiff,
|
||||
/// Style to apply to the selected item
|
||||
highlight_style: Style,
|
||||
/// Tab divider
|
||||
divider: Span<'a>,
|
||||
}
|
||||
|
@ -46,7 +46,7 @@ impl<'a> Tabs<'a> {
|
|||
titles,
|
||||
selected: 0,
|
||||
style: Default::default(),
|
||||
highlight_style_diff: Default::default(),
|
||||
highlight_style: Default::default(),
|
||||
divider: Span::raw(symbols::line::VERTICAL),
|
||||
}
|
||||
}
|
||||
|
@ -66,14 +66,8 @@ impl<'a> Tabs<'a> {
|
|||
self
|
||||
}
|
||||
|
||||
#[deprecated(since = "0.10.0", note = "You should use `Tabs::highlight_style_diff`")]
|
||||
pub fn highlight_style(mut self, style: Style) -> Tabs<'a> {
|
||||
self.highlight_style_diff = StyleDiff::from(style);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn highlight_style_diff(mut self, diff: StyleDiff) -> Tabs<'a> {
|
||||
self.highlight_style_diff = diff;
|
||||
self.highlight_style = style;
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -88,6 +82,7 @@ impl<'a> Tabs<'a> {
|
|||
|
||||
impl<'a> Widget for Tabs<'a> {
|
||||
fn render(mut self, area: Rect, buf: &mut Buffer) {
|
||||
buf.set_style(area, self.style);
|
||||
let tabs_area = match self.block.take() {
|
||||
Some(b) => {
|
||||
let inner_area = b.inner(area);
|
||||
|
@ -101,35 +96,33 @@ impl<'a> Widget for Tabs<'a> {
|
|||
return;
|
||||
}
|
||||
|
||||
buf.set_background(tabs_area, self.style.bg);
|
||||
|
||||
let mut x = tabs_area.left();
|
||||
let titles_length = self.titles.len();
|
||||
for (i, mut title) in self.titles.into_iter().enumerate() {
|
||||
for (i, title) in self.titles.into_iter().enumerate() {
|
||||
let last_title = titles_length - 1 == i;
|
||||
if i == self.selected {
|
||||
for span in &mut title.0 {
|
||||
span.style_diff = span.style_diff.patch(self.highlight_style_diff);
|
||||
}
|
||||
}
|
||||
x = x.saturating_add(1);
|
||||
let remaining_width = tabs_area.right().saturating_sub(x);
|
||||
if remaining_width == 0 {
|
||||
break;
|
||||
}
|
||||
let pos = buf.set_spans(x, tabs_area.top(), &title, remaining_width, self.style);
|
||||
let pos = buf.set_spans(x, tabs_area.top(), &title, remaining_width);
|
||||
if i == self.selected {
|
||||
buf.set_style(
|
||||
Rect {
|
||||
x,
|
||||
y: tabs_area.top(),
|
||||
width: pos.0.saturating_sub(x),
|
||||
height: 1,
|
||||
},
|
||||
self.highlight_style,
|
||||
);
|
||||
}
|
||||
x = pos.0.saturating_add(1);
|
||||
let remaining_width = tabs_area.right().saturating_sub(x);
|
||||
if remaining_width == 0 || last_title {
|
||||
break;
|
||||
}
|
||||
let pos = buf.set_span(
|
||||
x,
|
||||
tabs_area.top(),
|
||||
&self.divider,
|
||||
remaining_width,
|
||||
self.style,
|
||||
);
|
||||
let pos = buf.set_span(x, tabs_area.top(), &self.divider, remaining_width);
|
||||
x = pos.0;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@ use tui::{
|
|||
backend::TestBackend,
|
||||
buffer::Buffer,
|
||||
layout::Rect,
|
||||
style::{Color, StyleDiff},
|
||||
style::{Color, Style},
|
||||
text::Span,
|
||||
widgets::{Block, Borders},
|
||||
Terminal,
|
||||
|
@ -15,10 +15,7 @@ fn widgets_block_renders() {
|
|||
terminal
|
||||
.draw(|f| {
|
||||
let block = Block::default()
|
||||
.title(Span::styled(
|
||||
"Title",
|
||||
StyleDiff::default().fg(Color::LightBlue),
|
||||
))
|
||||
.title(Span::styled("Title", Style::default().fg(Color::LightBlue)))
|
||||
.borders(Borders::ALL);
|
||||
f.render_widget(
|
||||
block,
|
||||
|
|
|
@ -2,7 +2,7 @@ use tui::{
|
|||
backend::TestBackend,
|
||||
buffer::Buffer,
|
||||
layout::Rect,
|
||||
style::{Color, StyleDiff},
|
||||
style::{Color, Style},
|
||||
symbols,
|
||||
widgets::{Block, Borders, List, ListItem, ListState},
|
||||
Terminal,
|
||||
|
@ -23,13 +23,13 @@ fn widgets_list_should_highlight_the_selected_item() {
|
|||
ListItem::new("Item 3"),
|
||||
];
|
||||
let list = List::new(items)
|
||||
.highlight_style_diff(StyleDiff::default().bg(Color::Yellow))
|
||||
.highlight_style(Style::default().bg(Color::Yellow))
|
||||
.highlight_symbol(">> ");
|
||||
f.render_stateful_widget(list, size, &mut state);
|
||||
})
|
||||
.unwrap();
|
||||
let mut expected = Buffer::with_lines(vec![" Item 1 ", ">> Item 2 ", " Item 3 "]);
|
||||
for x in 0..9 {
|
||||
for x in 0..10 {
|
||||
expected.get_mut(x, 1).set_bg(Color::Yellow);
|
||||
}
|
||||
terminal.backend().assert_buffer(&expected);
|
||||
|
|
Loading…
Reference in a new issue