use crate::colors::Color;
#[cfg(feature = "complex_colored_text")]
use crate::colors::ColorLayer;
use cotis::utils::OwnedOrRef;
use cotis::utils::OwnedOrRef::Ref;
#[cfg(feature = "serde")]
use serde::{Deserialize, Serialize};
use std::ops::Range;
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TextConfig {
pub font_id: u16,
pub font_size: f32,
pub letter_spacing: f32,
pub line_height: f32,
pub wrap_mode: TextElementConfigWrapMode,
pub alignment: TextAlignment,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(not(feature = "complex_colored_text"), derive(Copy))]
pub struct TextStyle {
#[cfg(not(feature = "complex_colored_text"))]
pub color: Color,
#[cfg(feature = "complex_colored_text")]
pub color: ColorLayer,
}
impl Default for TextConfig {
fn default() -> Self {
Self {
font_id: 0,
font_size: 0.,
letter_spacing: 0.,
line_height: 0.,
wrap_mode: TextElementConfigWrapMode::Words,
alignment: TextAlignment::Left,
}
}
}
impl Default for TextStyle {
fn default() -> Self {
Self {
#[cfg(not(feature = "complex_colored_text"))]
color: Color::rgb(0.0, 0.0, 0.0),
#[cfg(feature = "complex_colored_text")]
color: ColorLayer::Solid(Color::rgb(0.0, 0.0, 0.0)),
}
}
}
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum TextElementConfigWrapMode {
Words,
Newline,
None,
}
#[derive(Debug, Clone, Copy)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub enum TextAlignment {
Left,
Center,
Right,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct TextElementConfig<'a> {
pub text: OwnedOrRef<'a, str>,
pub config: TextConfig,
pub style: TextStyle,
}
#[derive(Debug, Clone)]
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
#[cfg_attr(not(feature = "complex_colored_text"), derive(Copy, Default))]
pub struct TextConfigStylePair {
pub config: TextConfig,
pub style: TextStyle,
}
impl<'a> Default for TextElementConfig<'a> {
fn default() -> Self {
Self {
text: Ref(""),
config: TextConfig::default(),
style: Default::default(),
}
}
}
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
pub struct RichTextElementConfig<'a> {
pub text: OwnedOrRef<'a, str>,
pub default_config: TextConfigStylePair,
pub configs: Vec<TextConfigStylePair>,
pub config_ranges: Vec<(Range<usize>, usize)>,
}
pub struct RichTextElementBuilder<'a> {
text: OwnedOrRef<'a, str>,
default_config: TextConfigStylePair,
configs: Vec<TextConfigStylePair>,
config_ranges: Vec<(Range<usize>, usize)>,
}
impl<'a> RichTextElementBuilder<'a> {
pub fn new(text: OwnedOrRef<'a, str>, default_config: TextConfigStylePair) -> Self {
Self {
text,
default_config,
configs: vec![],
config_ranges: vec![],
}
}
pub fn add_config(&mut self, config: TextConfigStylePair) -> usize {
self.configs.push(config);
self.config_ranges.len() - 1
}
pub fn configure_range(&mut self, range: Range<usize>, config_index: usize) {
assert!(range.end < self.text.as_ref().len());
assert!(config_index <= self.config_ranges.len());
self.config_ranges.push((range, config_index));
}
pub fn into_config(self) -> RichTextElementConfig<'a> {
RichTextElementConfig {
text: self.text,
default_config: self.default_config,
configs: self.configs,
config_ranges: self.config_ranges,
}
}
}