use crate::SpannedStrExt;
use cursive_core::{
Printer, Vec2,
theme::{
BaseColor,
Color,
ColorStyle,
ColorType
},
utils::{
markup::StyledString,
lines::spans::{Row, LinesIterator}
}
};
use unicode_width::UnicodeWidthStr;
mod button;
mod select_view;
pub use button::*;
pub use select_view::*;
#[derive(Clone)]
enum ButtonContent {
SingleRow(StyledString),
MultiRow(Vec<Row>, StyledString)
}
impl ButtonContent {
fn new<S: Into<StyledString>>(label: S) -> ButtonContent {
Self::SingleRow(label.into())
}
fn get_content(&self) -> &StyledString {
match self {
Self::SingleRow(ref label) | Self::MultiRow(_, ref label) => label,
}
}
fn get_content_mut(&mut self) -> &mut StyledString {
match self {
Self::SingleRow(ref mut label) | Self::MultiRow(_, ref mut label) => label,
}
}
fn set_content<S: Into<StyledString>>(&mut self, new_label: S) {
match self {
Self::SingleRow(ref mut label) | Self::MultiRow(_, ref mut label) => *label = new_label.into()
}
}
fn fit_to_width(&mut self, width: usize) {
if width == 0 { return; }
let content = self.get_content().clone();
if width < content.width() || content.source().contains('\n'){
let rows: Vec<Row> = LinesIterator::new(content.as_spanned_str(), width).collect();
*self = Self::MultiRow(rows, content);
}
else { *self = Self::SingleRow(content); }
}
fn size(&self, brackets: bool) -> Vec2 {
match self {
Self::SingleRow(ref label) => (label.width() + if brackets { 2 } else { 0 }, 1).into(),
Self::MultiRow(ref rows, _) => {
let width = rows
.iter()
.map(|row| row.width)
.max()
.unwrap_or(0);
let height = rows.len();
if let Some(first_width) = rows.iter().map(|row| row.width).next() {
if first_width >= width && brackets {
return (width + 1, height).into();
}
}
if let Some(last_width) = rows.iter().map(|row| row.width).last() {
if last_width >= width && brackets {
return (width + 1, height).into();
}
}
(width, height).into()
}
}
}
fn draw(&self, printer: &Printer, loc: Vec2, enabled: bool, focused: bool, brackets: bool) {
if printer.size.x == 0 { return; }
let style = if !enabled { ColorStyle::secondary() }
else if focused { ColorStyle::highlight() }
else { ColorStyle::primary() };
printer.with_style(style, |printer| {
match self {
Self::SingleRow(ref label) => {
if brackets {
let len = label.width();
printer.print(loc, "<");
printer.print(loc + (len + 1, 0), ">");
}
let mut x = brackets as usize;
for span in label.spans() {
let new_style = if focused && enabled {
if matches!(span.attr.color.front, ColorType::InheritParent | ColorType::Palette(_)) && matches!(span.attr.color.front, ColorType::InheritParent | ColorType::Palette(_)) {
style
}
else { ColorStyle::new(Color::Dark(BaseColor::Black), span.attr.color.front) }
}
else if enabled { span.attr.color }
else {
let back = span.attr.color.back;
match span.attr.color.front {
ColorType::Color(Color::Light(base)) => ColorStyle::new(Color::Dark(base), back),
c => ColorStyle::from(c)
}
};
printer.with_style(new_style, |printer| printer.print(loc + (x, 0), span.content));
x += span.content.width();
}
}
Self::MultiRow(ref rows, ref label) => {
for (y, row) in rows.iter().enumerate() {
printer.with_style(style, |printer| {
printer.print_hline(loc + (0, y), self.size(brackets).x, " ");
if brackets {
if y == 0 {
printer.print(loc, "<");
}
else if y == rows.len() - 1 {
printer.print(loc + (row.width, y), ">");
}
}
});
let mut x = (brackets && y == 0) as usize;
for span in row.resolve(label.as_spanned_str()) {
let new_style = if focused && enabled {
if matches!(span.attr.color.front, ColorType::InheritParent | ColorType::Palette(_)) && matches!(span.attr.color.front, ColorType::InheritParent | ColorType::Palette(_)) {
style
}
else { ColorStyle::new(Color::Dark(BaseColor::Black), span.attr.color.front) }
}
else if enabled { span.attr.color }
else {
let back = span.attr.color.back;
match span.attr.color.front {
ColorType::Color(Color::Light(base)) => ColorStyle::new(Color::Dark(base), back),
c => ColorStyle::from(c)
}
};
printer.with_style(new_style, |printer| printer.print(loc + (x, y), span.content));
x += span.content.width();
}
}
}
}
});
}
}