Implement rich_text widget and markdown example

This commit is contained in:
Héctor Ramón Jiménez 2024-07-17 22:04:11 +02:00
parent ffb520fb37
commit 910eb72a06
No known key found for this signature in database
GPG key ID: 7CC46565708259A7
11 changed files with 787 additions and 99 deletions

View file

@ -10,6 +10,7 @@ pub use paragraph::Paragraph;
use crate::alignment;
use crate::{Color, Pixels, Point, Rectangle, Size};
use std::borrow::Cow;
use std::hash::{Hash, Hasher};
/// A paragraph.
@ -220,3 +221,150 @@ pub trait Renderer: crate::Renderer {
clip_bounds: Rectangle,
);
}
/// A span of text.
#[derive(Debug, Clone, PartialEq)]
pub struct Span<'a, Font = crate::Font> {
/// The [`Fragment`] of text.
pub text: Fragment<'a>,
/// The size of the [`Span`] in [`Pixels`].
pub size: Option<Pixels>,
/// The [`LineHeight`] of the [`Span`].
pub line_height: Option<LineHeight>,
/// The font of the [`Span`].
pub font: Option<Font>,
/// The [`Color`] of the [`Span`].
pub color: Option<Color>,
}
impl<'a, Font> Span<'a, Font> {
/// Creates a new [`Span`] of text with the given text fragment.
pub fn new(fragment: impl IntoFragment<'a>) -> Self {
Self {
text: fragment.into_fragment(),
size: None,
line_height: None,
font: None,
color: None,
}
}
/// Sets the size of the [`Span`].
pub fn size(mut self, size: impl Into<Pixels>) -> Self {
self.size = Some(size.into());
self
}
/// Sets the [`LineHeight`] of the [`Span`].
pub fn line_height(mut self, line_height: impl Into<LineHeight>) -> Self {
self.line_height = Some(line_height.into());
self
}
/// Sets the font of the [`Span`].
pub fn font(mut self, font: impl Into<Font>) -> Self {
self.font = Some(font.into());
self
}
/// Sets the [`Color`] of the [`Span`].
pub fn color(mut self, color: impl Into<Color>) -> Self {
self.color = Some(color.into());
self
}
/// Turns the [`Span`] into a static one.
pub fn to_static(self) -> Span<'static, Font> {
Span {
text: Cow::Owned(self.text.into_owned()),
size: self.size,
line_height: self.line_height,
font: self.font,
color: self.color,
}
}
}
impl<'a, Font> From<&'a str> for Span<'a, Font> {
fn from(value: &'a str) -> Self {
Span::new(value)
}
}
/// A fragment of [`Text`].
///
/// This is just an alias to a string that may be either
/// borrowed or owned.
pub type Fragment<'a> = Cow<'a, str>;
/// A trait for converting a value to some text [`Fragment`].
pub trait IntoFragment<'a> {
/// Converts the value to some text [`Fragment`].
fn into_fragment(self) -> Fragment<'a>;
}
impl<'a> IntoFragment<'a> for Fragment<'a> {
fn into_fragment(self) -> Fragment<'a> {
self
}
}
impl<'a, 'b> IntoFragment<'a> for &'a Fragment<'b> {
fn into_fragment(self) -> Fragment<'a> {
Fragment::Borrowed(self)
}
}
impl<'a> IntoFragment<'a> for &'a str {
fn into_fragment(self) -> Fragment<'a> {
Fragment::Borrowed(self)
}
}
impl<'a> IntoFragment<'a> for &'a String {
fn into_fragment(self) -> Fragment<'a> {
Fragment::Borrowed(self.as_str())
}
}
impl<'a> IntoFragment<'a> for String {
fn into_fragment(self) -> Fragment<'a> {
Fragment::Owned(self)
}
}
macro_rules! into_fragment {
($type:ty) => {
impl<'a> IntoFragment<'a> for $type {
fn into_fragment(self) -> Fragment<'a> {
Fragment::Owned(self.to_string())
}
}
impl<'a> IntoFragment<'a> for &$type {
fn into_fragment(self) -> Fragment<'a> {
Fragment::Owned(self.to_string())
}
}
};
}
into_fragment!(char);
into_fragment!(bool);
into_fragment!(u8);
into_fragment!(u16);
into_fragment!(u32);
into_fragment!(u64);
into_fragment!(u128);
into_fragment!(usize);
into_fragment!(i8);
into_fragment!(i16);
into_fragment!(i32);
into_fragment!(i64);
into_fragment!(i128);
into_fragment!(isize);
into_fragment!(f32);
into_fragment!(f64);