Unify Link and Message generics in text::Rich

This commit is contained in:
Héctor Ramón Jiménez 2024-07-24 10:12:33 +02:00
parent a8c772eb8a
commit faa5d0c58d
No known key found for this signature in database
GPG key ID: 4C07CEC81AFA161F
4 changed files with 29 additions and 72 deletions

View file

@ -64,11 +64,8 @@ impl Markdown {
.padding(10) .padding(10)
.font(Font::MONOSPACE); .font(Font::MONOSPACE);
let preview = markdown( let preview = markdown(&self.items, markdown::Settings::default())
&self.items, .map(Message::LinkClicked);
markdown::Settings::default(),
Message::LinkClicked,
);
row![editor, scrollable(preview).spacing(10).height(Fill)] row![editor, scrollable(preview).spacing(10).height(Fill)]
.spacing(10) .spacing(10)

View file

@ -683,11 +683,11 @@ where
/// Creates a new [`Rich`] text widget with the provided spans. /// Creates a new [`Rich`] text widget with the provided spans.
/// ///
/// [`Rich`]: text::Rich /// [`Rich`]: text::Rich
pub fn rich_text<'a, Message, Link, Theme, Renderer>( pub fn rich_text<'a, Link, Theme, Renderer>(
spans: impl Into<Cow<'a, [text::Span<'a, Link, Renderer::Font>]>>, spans: impl Into<Cow<'a, [text::Span<'a, Link, Renderer::Font>]>>,
) -> text::Rich<'a, Message, Link, Theme, Renderer> ) -> text::Rich<'a, Link, Theme, Renderer>
where where
Link: Clone, Link: Clone + 'static,
Theme: text::Catalog + 'a, Theme: text::Catalog + 'a,
Renderer: core::text::Renderer, Renderer: core::text::Renderer,
{ {

View file

@ -332,13 +332,11 @@ impl Default for Settings {
/// Display a bunch of Markdown items. /// Display a bunch of Markdown items.
/// ///
/// You can obtain the items with [`parse`]. /// You can obtain the items with [`parse`].
pub fn view<'a, Message, Renderer>( pub fn view<'a, Renderer>(
items: impl IntoIterator<Item = &'a Item>, items: impl IntoIterator<Item = &'a Item>,
settings: Settings, settings: Settings,
on_link: impl Fn(Url) -> Message + Copy + 'a, ) -> Element<'a, Url, Theme, Renderer>
) -> Element<'a, Message, Theme, Renderer>
where where
Message: 'a,
Renderer: core::text::Renderer<Font = Font> + 'a, Renderer: core::text::Renderer<Font = Font> + 'a,
{ {
let Settings { let Settings {
@ -356,7 +354,7 @@ where
let blocks = items.into_iter().enumerate().map(|(i, item)| match item { let blocks = items.into_iter().enumerate().map(|(i, item)| match item {
Item::Heading(level, heading) => { Item::Heading(level, heading) => {
container(rich_text(heading).on_link(on_link).size(match level { container(rich_text(heading).size(match level {
pulldown_cmark::HeadingLevel::H1 => h1_size, pulldown_cmark::HeadingLevel::H1 => h1_size,
pulldown_cmark::HeadingLevel::H2 => h2_size, pulldown_cmark::HeadingLevel::H2 => h2_size,
pulldown_cmark::HeadingLevel::H3 => h3_size, pulldown_cmark::HeadingLevel::H3 => h3_size,
@ -372,11 +370,11 @@ where
.into() .into()
} }
Item::Paragraph(paragraph) => { Item::Paragraph(paragraph) => {
rich_text(paragraph).on_link(on_link).size(text_size).into() rich_text(paragraph).size(text_size).into()
} }
Item::List { start: None, items } => { Item::List { start: None, items } => {
column(items.iter().map(|items| { column(items.iter().map(|items| {
row![text("").size(text_size), view(items, settings, on_link)] row![text("").size(text_size), view(items, settings)]
.spacing(spacing) .spacing(spacing)
.into() .into()
})) }))
@ -389,7 +387,7 @@ where
} => column(items.iter().enumerate().map(|(i, items)| { } => column(items.iter().enumerate().map(|(i, items)| {
row![ row![
text!("{}.", i as u64 + *start).size(text_size), text!("{}.", i as u64 + *start).size(text_size),
view(items, settings, on_link) view(items, settings)
] ]
.spacing(spacing) .spacing(spacing)
.into() .into()
@ -399,10 +397,7 @@ where
Item::CodeBlock(code) => container( Item::CodeBlock(code) => container(
scrollable( scrollable(
container( container(
rich_text(code) rich_text(code).font(Font::MONOSPACE).size(code_size),
.font(Font::MONOSPACE)
.size(code_size)
.on_link(on_link),
) )
.padding(spacing.0 / 2.0), .padding(spacing.0 / 2.0),
) )

View file

@ -17,13 +17,8 @@ use std::borrow::Cow;
/// A bunch of [`Rich`] text. /// A bunch of [`Rich`] text.
#[allow(missing_debug_implementations)] #[allow(missing_debug_implementations)]
pub struct Rich< pub struct Rich<'a, Link, Theme = crate::Theme, Renderer = crate::Renderer>
'a, where
Message,
Link = (),
Theme = crate::Theme,
Renderer = crate::Renderer,
> where
Link: Clone + 'static, Link: Clone + 'static,
Theme: Catalog, Theme: Catalog,
Renderer: core::text::Renderer, Renderer: core::text::Renderer,
@ -37,11 +32,9 @@ pub struct Rich<
align_x: alignment::Horizontal, align_x: alignment::Horizontal,
align_y: alignment::Vertical, align_y: alignment::Vertical,
class: Theme::Class<'a>, class: Theme::Class<'a>,
on_link: Option<Box<dyn Fn(Link) -> Message + 'a>>,
} }
impl<'a, Message, Link, Theme, Renderer> impl<'a, Link, Theme, Renderer> Rich<'a, Link, Theme, Renderer>
Rich<'a, Message, Link, Theme, Renderer>
where where
Link: Clone + 'static, Link: Clone + 'static,
Theme: Catalog, Theme: Catalog,
@ -59,7 +52,6 @@ where
align_x: alignment::Horizontal::Left, align_x: alignment::Horizontal::Left,
align_y: alignment::Vertical::Top, align_y: alignment::Vertical::Top,
class: Theme::default(), class: Theme::default(),
on_link: None,
} }
} }
@ -155,21 +147,6 @@ where
self.style(move |_theme| Style { color }) self.style(move |_theme| Style { color })
} }
/// Sets the message handler for link clicks on the [`Rich`] text.
pub fn on_link(mut self, on_link: impl Fn(Link) -> Message + 'a) -> Self {
self.on_link = Some(Box::new(on_link));
self
}
/// Sets the message handler for link clicks on the [`Rich`] text.
pub fn on_link_maybe(
mut self,
on_link: Option<impl Fn(Link) -> Message + 'a>,
) -> Self {
self.on_link = on_link.map(|on_link| Box::new(on_link) as _);
self
}
/// Sets the default style class of the [`Rich`] text. /// Sets the default style class of the [`Rich`] text.
#[cfg(feature = "advanced")] #[cfg(feature = "advanced")]
#[must_use] #[must_use]
@ -188,10 +165,9 @@ where
} }
} }
impl<'a, Message, Link, Theme, Renderer> Default impl<'a, Link, Theme, Renderer> Default for Rich<'a, Link, Theme, Renderer>
for Rich<'a, Message, Link, Theme, Renderer>
where where
Link: Clone + 'static, Link: Clone + 'a,
Theme: Catalog, Theme: Catalog,
Renderer: core::text::Renderer, Renderer: core::text::Renderer,
{ {
@ -206,8 +182,8 @@ struct State<Link, P: Paragraph> {
paragraph: P, paragraph: P,
} }
impl<'a, Message, Link, Theme, Renderer> Widget<Message, Theme, Renderer> impl<'a, Link, Theme, Renderer> Widget<Link, Theme, Renderer>
for Rich<'a, Message, Link, Theme, Renderer> for Rich<'a, Link, Theme, Renderer>
where where
Link: Clone + 'static, Link: Clone + 'static,
Theme: Catalog, Theme: Catalog,
@ -288,13 +264,9 @@ where
cursor: mouse::Cursor, cursor: mouse::Cursor,
_renderer: &Renderer, _renderer: &Renderer,
_clipboard: &mut dyn Clipboard, _clipboard: &mut dyn Clipboard,
shell: &mut Shell<'_, Message>, shell: &mut Shell<'_, Link>,
_viewport: &Rectangle, _viewport: &Rectangle,
) -> event::Status { ) -> event::Status {
let Some(on_link_click) = self.on_link.as_ref() else {
return event::Status::Ignored;
};
match event { match event {
Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => { Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) => {
if let Some(position) = cursor.position_in(layout.bounds()) { if let Some(position) = cursor.position_in(layout.bounds()) {
@ -326,7 +298,7 @@ where
.get(span) .get(span)
.and_then(|span| span.link.clone()) .and_then(|span| span.link.clone())
{ {
shell.publish(on_link_click(link)); shell.publish(link);
} }
} }
_ => {} _ => {}
@ -348,10 +320,6 @@ where
_viewport: &Rectangle, _viewport: &Rectangle,
_renderer: &Renderer, _renderer: &Renderer,
) -> mouse::Interaction { ) -> mouse::Interaction {
if self.on_link.is_none() {
return mouse::Interaction::None;
}
if let Some(position) = cursor.position_in(layout.bounds()) { if let Some(position) = cursor.position_in(layout.bounds()) {
let state = tree let state = tree
.state .state
@ -436,11 +404,10 @@ where
}) })
} }
impl<'a, Message, Link, Theme, Renderer> impl<'a, Link, Theme, Renderer> FromIterator<Span<'a, Link, Renderer::Font>>
FromIterator<Span<'a, Link, Renderer::Font>> for Rich<'a, Link, Theme, Renderer>
for Rich<'a, Message, Link, Theme, Renderer>
where where
Link: Clone + 'static, Link: Clone + 'a,
Theme: Catalog, Theme: Catalog,
Renderer: core::text::Renderer, Renderer: core::text::Renderer,
{ {
@ -454,18 +421,16 @@ where
} }
} }
impl<'a, Message, Link, Theme, Renderer> impl<'a, Link, Theme, Renderer> From<Rich<'a, Link, Theme, Renderer>>
From<Rich<'a, Message, Link, Theme, Renderer>> for Element<'a, Link, Theme, Renderer>
for Element<'a, Message, Theme, Renderer>
where where
Message: 'a, Link: Clone + 'a,
Link: Clone + 'static,
Theme: Catalog + 'a, Theme: Catalog + 'a,
Renderer: core::text::Renderer + 'a, Renderer: core::text::Renderer + 'a,
{ {
fn from( fn from(
text: Rich<'a, Message, Link, Theme, Renderer>, text: Rich<'a, Link, Theme, Renderer>,
) -> Element<'a, Message, Theme, Renderer> { ) -> Element<'a, Link, Theme, Renderer> {
Element::new(text) Element::new(text)
} }
} }