iced_selection/lib.rs
1//! A text selection API built around [`iced`]'s [`Paragraph`].
2//!
3//! [`iced`]: https://iced.rs
4//! [`Paragraph`]: https://docs.iced.rs/iced_graphics/text/paragraph/struct.Paragraph.html
5
6mod click;
7#[cfg(feature = "markdown")]
8pub mod markdown;
9pub mod selection;
10pub mod text;
11
12use iced_widget::core;
13#[cfg(feature = "markdown")]
14pub use markdown::view as markdown;
15#[doc(no_inline)]
16pub use text::Text;
17
18/// Creates a new [`Text`] widget with the provided content.
19///
20/// [`Text`]: core::widget::Text
21///
22/// This macro uses the same syntax as [`format!`], but creates a new [`Text`] widget instead.
23///
24/// See [the formatting documentation in `std::fmt`](std::fmt)
25/// for details of the macro argument syntax.
26///
27/// # Examples
28///
29/// ```no_run,ignore
30/// use iced_selection::text;
31///
32/// enum Message {
33/// // ...
34/// }
35///
36/// fn view(_state: &State) -> impl Widget<Message> {
37/// let simple = text!("Hello, world!");
38///
39/// let keyword = text!("Hello, {}", "world!");
40///
41/// let planet = "Earth";
42/// let local_variable = text!("Hello, {planet}!");
43/// // ...
44/// }
45/// ```
46#[macro_export]
47macro_rules! text {
48 ($($arg:tt)*) => {
49 $crate::Text::new(format!($($arg)*))
50 };
51}
52
53/// Creates some [`Rich`] text with the given spans.
54///
55/// # Example
56/// ```no_run,ignore
57/// use iced::font;
58/// use iced_selection::{rich_text, span};
59/// use iced::{color, never, Font};
60///
61/// #[derive(Debug, Clone)]
62/// enum Message {
63/// // ...
64/// }
65///
66/// fn view(state: &State) -> impl Widget<'_, Message> {
67/// rich_text![
68/// span("I am red!").color(color!(0xff0000)),
69/// span(" "),
70/// span("And I am bold!").font(Font { weight: font::Weight::Bold, ..Font::default() }),
71/// ]
72/// .on_link_click(never)
73/// .size(20)
74/// .into()
75/// }
76/// ```
77///
78/// [`Rich`]: crate::text::Rich
79#[macro_export]
80macro_rules! rich_text {
81 () => (
82 $crate::text::Rich::new()
83 );
84 ($($x:expr),+ $(,)?) => (
85 $crate::text::Rich::from_iter([$($crate::text::Span::from($x)),+])
86 );
87}
88
89/// Creates a new [`Span`] of text with the provided content.
90///
91/// A [`Span`] is a fragment of some [`Rich`] text.
92///
93/// This macro uses the same syntax as [`format!`], but creates a new [`Span`] widget instead.
94///
95/// See [the formatting documentation in `std::fmt`](std::fmt)
96/// for details of the macro argument syntax.
97///
98/// # Example
99/// ```no_run,ignore
100/// use iced::font;
101/// use iced_selection::{rich_text, span};
102/// use iced::{color, never, Font};
103///
104/// #[derive(Debug, Clone)]
105/// enum Message {
106/// // ...
107/// }
108///
109/// fn view(state: &State) -> impl Widget<'_, Message> {
110/// rich_text![
111/// span!("I am {}!", red).color(color!(0xff0000)),
112/// " ",
113/// span!("And I am bold!").font(Font { weight: font::Weight::Bold, ..Font::default() }),
114/// ]
115/// .on_link_click(never)
116/// .size(20)
117/// .into()
118/// }
119/// ```
120///
121/// [`Rich`]: crate::text::Rich
122/// [`Span`]: crate::text::Span
123#[macro_export]
124macro_rules! span {
125 ($($arg:tt)*) => {
126 $crate::text::Span::new(format!($($arg)*))
127 };
128}
129
130/// Creates a new [`Text`] widget with the provided content.
131///
132/// # Example
133/// ```no_run,ignore
134/// use iced_selection::text;
135///
136/// enum Message {
137/// // ...
138/// }
139///
140/// fn view(state: &State) -> impl Widget<'_, Message> {
141/// text("Hello, this is iced!")
142/// .size(20)
143/// .into()
144/// }
145/// ```
146pub fn text<'a, Theme>(text: impl text::IntoFragment<'a>) -> Text<'a, Theme>
147where
148 Theme: text::Catalog + 'a,
149{
150 Text::new(text)
151}
152
153/// Creates some [`Rich`] text with the given spans.
154///
155/// [`Rich`]: crate::text::Rich
156///
157/// # Example
158/// ```no_run,ignore
159/// use iced::font;
160/// use iced_selection::{rich_text, span};
161/// use iced::{color, never, Font};
162///
163/// #[derive(Debug, Clone)]
164/// enum Message {
165/// LinkClicked(&'static str),
166/// // ...
167/// }
168///
169/// fn view(state: &State) -> impl Widget<'_, Message> {
170/// rich_text([
171/// span("I am red!").color(color!(0xff0000)),
172/// span(" "),
173/// span("And I am bold!").font(Font { weight: font::Weight::Bold, ..Font::default() }),
174/// ])
175/// .on_link_click(never)
176/// .size(20)
177/// .into()
178/// }
179/// ```
180pub fn rich_text<'a, Link, Message, Theme>(
181 spans: impl AsRef<[text::Span<'a, Link>]> + 'a,
182) -> text::Rich<'a, Link, Message, Theme>
183where
184 Link: Clone + 'static,
185 Theme: text::Catalog + 'a,
186{
187 text::Rich::with_spans(spans)
188}
189
190/// Creates a new [`Span`] of text with the provided content.
191///
192/// A [`Span`] is a fragment of some [`Rich`] text.
193///
194/// [`Rich`]: crate::text::Rich
195/// [`Span`]: crate::text::Span
196///
197/// # Example
198/// ```no_run,ignore
199/// use iced::font;
200/// use iced_selection::{rich_text, span};
201/// use iced::{color, never, Font};
202///
203/// #[derive(Debug, Clone)]
204/// enum Message {
205/// // ...
206/// }
207///
208/// fn view(state: &State) -> impl Widget<'_, Message> {
209/// rich_text![
210/// span("I am red!").color(color!(0xff0000)),
211/// " ",
212/// span("And I am bold!").font(Font { weight: font::Weight::Bold, ..Font::default() }),
213/// ]
214/// .on_link_click(never)
215/// .size(20)
216/// .into()
217/// }
218/// ```
219pub fn span<'a, Link>(
220 text: impl text::IntoFragment<'a>,
221) -> text::Span<'a, Link> {
222 text::Span::new(text)
223}