use std::borrow::Cow;
use ratatui_core::style::{Color, Modifier, Style, Styled};
use ratatui_core::text::{Line, Span, Text};
#[cfg(feature = "gradients")]
use unicode_segmentation::UnicodeSegmentation;
use crate::color::OpalineColor;
#[cfg(feature = "gradients")]
use crate::gradient::Gradient;
use crate::style::OpalineStyle;
use crate::theme::Theme;
impl From<OpalineColor> for Color {
fn from(c: OpalineColor) -> Self {
Color::Rgb(c.r, c.g, c.b)
}
}
impl From<&OpalineColor> for Color {
fn from(c: &OpalineColor) -> Self {
Color::Rgb(c.r, c.g, c.b)
}
}
impl From<OpalineColor> for Style {
fn from(c: OpalineColor) -> Self {
Style::default().fg(Color::Rgb(c.r, c.g, c.b))
}
}
impl From<OpalineStyle> for Style {
fn from(s: OpalineStyle) -> Self {
let mut style = Style::default();
if let Some(fg) = s.fg {
style = style.fg(Color::Rgb(fg.r, fg.g, fg.b));
}
if let Some(bg) = s.bg {
style = style.bg(Color::Rgb(bg.r, bg.g, bg.b));
}
let modifiers = Modifier::from_bits_truncate(s.modifier_bits());
if !modifiers.is_empty() {
style = style.add_modifier(modifiers);
}
style
}
}
impl From<&OpalineStyle> for Style {
fn from(s: &OpalineStyle) -> Self {
s.clone().into()
}
}
impl Styled for OpalineStyle {
type Item = Style;
fn style(&self) -> Style {
Style::from(self)
}
fn set_style<S: Into<Style>>(self, style: S) -> Style {
Style::from(self).patch(style)
}
}
impl Theme {
pub fn span<'a>(&self, style_name: &str, content: impl Into<Cow<'a, str>>) -> Span<'a> {
Span::styled(content, Style::from(self.style(style_name)))
}
pub fn line<'a>(&self, style_name: &str, content: impl Into<Cow<'a, str>>) -> Line<'a> {
Line::styled(content, Style::from(self.style(style_name)))
}
pub fn text<'a>(&self, style_name: &str, content: impl Into<Cow<'a, str>>) -> Text<'a> {
Text::styled(content, Style::from(self.style(style_name)))
}
#[cfg(feature = "gradients")]
pub fn gradient_text(&self, gradient_name: &str, content: &str) -> Line<'static> {
if let Some(gradient) = self.get_gradient(gradient_name) {
Line::from(gradient_spans(content, gradient))
} else {
Line::raw(content.to_string())
}
}
}
#[cfg(feature = "gradients")]
pub fn gradient_spans(text: &str, gradient: &Gradient) -> Vec<Span<'static>> {
let graphemes: Vec<&str> = text.graphemes(true).collect();
if graphemes.is_empty() {
return vec![];
}
let colors = gradient.generate(graphemes.len());
graphemes
.into_iter()
.zip(colors)
.map(|(grapheme, color)| {
Span::styled(
grapheme.to_string(),
Style::default().fg(Color::Rgb(color.r, color.g, color.b)),
)
})
.collect()
}
#[cfg(feature = "gradients")]
pub fn gradient_line(width: usize, ch: char, gradient: &Gradient) -> Vec<Span<'static>> {
if width == 0 {
return vec![];
}
let colors = gradient.generate(width);
colors
.into_iter()
.map(|color| {
Span::styled(
ch.to_string(),
Style::default().fg(Color::Rgb(color.r, color.g, color.b)),
)
})
.collect()
}
#[cfg(feature = "gradients")]
pub fn gradient_text_line(text: &str, gradient: &Gradient) -> Line<'static> {
Line::from(gradient_spans(text, gradient))
}
#[cfg(feature = "gradients")]
pub fn gradient_bar(width: usize, ch: char, gradient: &Gradient) -> Line<'static> {
Line::from(gradient_line(width, ch, gradient))
}