diff --git a/core/src/widget/text.rs b/core/src/widget/text.rs index 12f6956a39..53591e4191 100644 --- a/core/src/widget/text.rs +++ b/core/src/widget/text.rs @@ -21,7 +21,7 @@ where Theme: Catalog, Renderer: text::Renderer, { - content: Cow<'a, str>, + fragment: Fragment<'a>, size: Option, line_height: LineHeight, width: Length, @@ -39,9 +39,9 @@ where Renderer: text::Renderer, { /// Create a new fragment of [`Text`] with the given contents. - pub fn new(content: impl Into>) -> Self { + pub fn new(fragment: impl IntoFragment<'a>) -> Self { Text { - content: content.into(), + fragment: fragment.into_fragment(), size: None, line_height: LineHeight::default(), font: None, @@ -184,7 +184,7 @@ where limits, self.width, self.height, - &self.content, + &self.fragment, self.line_height, self.size, self.font, @@ -366,3 +366,69 @@ impl Catalog for Theme { class(self) } } + +/// 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 &'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); diff --git a/examples/lazy/src/main.rs b/examples/lazy/src/main.rs index 2d53df9335..c3f6b8de68 100644 --- a/examples/lazy/src/main.rs +++ b/examples/lazy/src/main.rs @@ -173,7 +173,7 @@ impl App { .style(button::danger); row![ - text(&item.name).color(item.color), + text(item.name.clone()).color(item.color), horizontal_space(), pick_list(Color::ALL, Some(item.color), move |color| { Message::ItemColorChanged(item.clone(), color) diff --git a/examples/tour/src/main.rs b/examples/tour/src/main.rs index a88c0dba0f..e3a2ca8796 100644 --- a/examples/tour/src/main.rs +++ b/examples/tour/src/main.rs @@ -357,7 +357,7 @@ impl<'a> Step { .into() } - fn container(title: &str) -> Column<'a, StepMessage> { + fn container(title: &str) -> Column<'_, StepMessage> { column![text(title).size(50)].spacing(20) } @@ -589,7 +589,7 @@ impl<'a> Step { value: &str, is_secure: bool, is_showing_icon: bool, - ) -> Column<'a, StepMessage> { + ) -> Column<'_, StepMessage> { let mut text_input = text_input("Type something to continue...", value) .on_input(StepMessage::InputChanged) .padding(10) @@ -674,7 +674,7 @@ fn ferris<'a>( .center_x() } -fn padded_button<'a, Message: Clone>(label: &str) -> Button<'a, Message> { +fn padded_button(label: &str) -> Button<'_, Message> { button(text(label)).padding([12, 24]) } diff --git a/examples/websocket/src/echo.rs b/examples/websocket/src/echo.rs index 281ed4bdcd..cd32cb6605 100644 --- a/examples/websocket/src/echo.rs +++ b/examples/websocket/src/echo.rs @@ -2,6 +2,7 @@ pub mod server; use iced::futures; use iced::subscription::{self, Subscription}; +use iced::widget::text; use futures::channel::mpsc; use futures::sink::SinkExt; @@ -136,16 +137,24 @@ impl Message { pub fn disconnected() -> Self { Message::Disconnected } + + pub fn as_str(&self) -> &str { + match self { + Message::Connected => "Connected successfully!", + Message::Disconnected => "Connection lost... Retrying...", + Message::User(message) => message.as_str(), + } + } } impl fmt::Display for Message { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self { - Message::Connected => write!(f, "Connected successfully!"), - Message::Disconnected => { - write!(f, "Connection lost... Retrying...") - } - Message::User(message) => write!(f, "{message}"), - } + f.write_str(self.as_str()) + } +} + +impl<'a> text::IntoFragment<'a> for &'a Message { + fn into_fragment(self) -> text::Fragment<'a> { + text::Fragment::Borrowed(self.as_str()) } } diff --git a/examples/websocket/src/main.rs b/examples/websocket/src/main.rs index 460d9a0839..b479fe8911 100644 --- a/examples/websocket/src/main.rs +++ b/examples/websocket/src/main.rs @@ -96,10 +96,8 @@ impl WebSocket { .into() } else { scrollable( - column( - self.messages.iter().cloned().map(text).map(Element::from), - ) - .spacing(10), + column(self.messages.iter().map(text).map(Element::from)) + .spacing(10), ) .id(MESSAGE_LOG.clone()) .height(Length::Fill) diff --git a/widget/src/helpers.rs b/widget/src/helpers.rs index 77b308821b..61789c193b 100644 --- a/widget/src/helpers.rs +++ b/widget/src/helpers.rs @@ -145,13 +145,26 @@ where /// /// [`Text`]: core::widget::Text pub fn text<'a, Theme, Renderer>( - text: impl ToString, + text: impl text::IntoFragment<'a>, ) -> Text<'a, Theme, Renderer> where Theme: text::Catalog + 'a, Renderer: core::text::Renderer, { - Text::new(text.to_string()) + Text::new(text) +} + +/// Creates a new [`Text`] widget that displays the provided value. +/// +/// [`Text`]: core::widget::Text +pub fn value<'a, Theme, Renderer>( + value: impl ToString, +) -> Text<'a, Theme, Renderer> +where + Theme: text::Catalog + 'a, + Renderer: core::text::Renderer, +{ + Text::new(value.to_string()) } /// Creates a new [`Checkbox`].