iced_widget/helpers.rs
1//! Helper functions to create pure widgets.
2use crate::button::{self, Button};
3use crate::checkbox::{self, Checkbox};
4use crate::combo_box::{self, ComboBox};
5use crate::container::{self, Container};
6use crate::core;
7use crate::core::theme;
8use crate::core::time::Instant;
9use crate::core::widget::Meta;
10use crate::core::widget::operation;
11use crate::core::{Element, Length, Size, Widget};
12use crate::float::{self, Float};
13use crate::keyed;
14use crate::lazy::Lazy;
15use crate::overlay;
16use crate::pane_grid::{self, PaneGrid};
17use crate::pick_list::{self, PickList};
18use crate::progress_bar::{self, ProgressBar};
19use crate::radio::{self, Radio};
20use crate::scrollable::{self, Scrollable};
21use crate::slider::{self, Slider};
22use crate::sticky::Sticky;
23use crate::text::{self, Text};
24use crate::text_editor::{self, TextEditor};
25use crate::text_input::{self, TextInput};
26use crate::toggler::{self, Toggler};
27use crate::tooltip::{self, Tooltip};
28use crate::transition::{self, Transition};
29use crate::vertical_slider::{self, VerticalSlider};
30use crate::{Column, Grid, Hover, MouseArea, Pin, Responsive, Row, Sensor, Space, Stack, Themer};
31
32use std::borrow::Borrow;
33use std::ops::RangeInclusive;
34
35pub use crate::component::component;
36pub use crate::table::table;
37
38/// Creates a [`Column`] with the given children.
39///
40/// Columns distribute their children vertically.
41///
42/// # Example
43/// ```no_run
44/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
45/// # use iced::widget::Widget;
46/// # pub type State = ();
47/// use iced::widget::{button, column};
48///
49/// #[derive(Debug, Clone)]
50/// enum Message {
51/// // ...
52/// }
53///
54/// fn view(state: &State) -> impl Widget<Message> {
55/// column![
56/// "I am on top!",
57/// button("I am in the center!"),
58/// "I am below.",
59/// ]
60/// }
61/// ```
62#[macro_export]
63macro_rules! column {
64 () => (
65 $crate::Column::new()
66 );
67 ($($x:expr),+ $(,)?) => (
68 $crate::Column::with_children([$($crate::core::Widget::_boxed($x)),+])
69 );
70}
71
72/// Creates a [`Row`] with the given children.
73///
74/// Rows distribute their children horizontally.
75///
76/// # Example
77/// ```no_run
78/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
79/// # use iced::widget::Widget;
80/// # pub type State = ();
81/// use iced::widget::{button, row};
82///
83/// #[derive(Debug, Clone)]
84/// enum Message {
85/// // ...
86/// }
87///
88/// fn view(state: &State) -> impl Widget<Message> {
89/// row![
90/// "I am to the left!",
91/// button("I am in the middle!"),
92/// "I am to the right!",
93/// ]
94/// }
95/// ```
96#[macro_export]
97macro_rules! row {
98 () => (
99 $crate::Row::new()
100 );
101 ($($x:expr),+ $(,)?) => (
102 $crate::Row::with_children([$($crate::core::Widget::_boxed($x)),+])
103 );
104}
105
106/// Creates a [`Stack`] with the given children.
107///
108/// [`Stack`]: crate::Stack
109#[macro_export]
110macro_rules! stack {
111 () => (
112 $crate::Stack::new()
113 );
114 ($($x:expr),+ $(,)?) => (
115 $crate::Stack::with_children([$($crate::core::Widget::_boxed($x)),+])
116 );
117}
118
119/// Creates a [`Grid`] with the given children.
120///
121/// [`Grid`]: crate::Grid
122#[macro_export]
123macro_rules! grid {
124 () => (
125 $crate::Grid::new()
126 );
127 ($($x:expr),+ $(,)?) => (
128 $crate::Grid::with_children([$($crate::core::Widget::_boxed($x)),+])
129 );
130}
131
132/// Creates a new [`Text`] widget with the provided content.
133///
134/// [`Text`]: core::widget::Text
135///
136/// This macro uses the same syntax as [`format!`], but creates a new [`Text`] widget instead.
137///
138/// See [the formatting documentation in `std::fmt`](std::fmt)
139/// for details of the macro argument syntax.
140///
141/// # Examples
142///
143/// ```no_run
144/// # mod iced {
145/// # pub mod widget {
146/// # macro_rules! text {
147/// # ($($arg:tt)*) => {iced_widget::text::<iced_widget::Theme>("text")}
148/// # }
149/// # pub(crate) use text;
150/// # }
151/// # }
152/// # use iced_widget::Widget;
153/// # pub type State = ();
154/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::core::Theme, ()>;
155/// use iced::widget::text;
156///
157/// enum Message {
158/// // ...
159/// }
160///
161/// fn view(_state: &State) -> impl Widget<Message> {
162/// let simple = text!("Hello, world!");
163///
164/// let keyword = text!("Hello, {}", "world!");
165///
166/// let planet = "Earth";
167/// let local_variable = text!("Hello, {planet}!");
168/// // ...
169/// # simple
170/// }
171/// ```
172#[macro_export]
173macro_rules! text {
174 ($($arg:tt)*) => {
175 $crate::Text::new(format!($($arg)*))
176 };
177}
178
179/// Creates some [`Rich`] text with the given spans.
180///
181/// [`Rich`]: text::Rich
182///
183/// # Example
184/// ```no_run
185/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::core::*; }
186/// # use iced::widget::Widget;
187/// # pub type State = ();
188/// use iced::font;
189/// use iced::widget::{rich_text, span};
190/// use iced::{color, never, Font};
191///
192/// #[derive(Debug, Clone)]
193/// enum Message {
194/// // ...
195/// }
196///
197/// fn view(state: &State) -> impl Widget<Message> {
198/// rich_text![
199/// span("I am red!").color(color!(0xff0000)),
200/// span(" "),
201/// span("And I am bold!").font(Font { weight: font::Weight::Bold, ..Font::default() }),
202/// ]
203/// .on_link_click(never)
204/// .size(20)
205/// }
206/// ```
207#[macro_export]
208macro_rules! rich_text {
209 () => (
210 $crate::text::Rich::new()
211 );
212 ($($x:expr),+ $(,)?) => (
213 $crate::text::Rich::from_iter([$($crate::text::Span::from($x)),+])
214 );
215}
216
217/// Creates a new [`Container`] with the provided content.
218///
219/// Containers let you align a widget inside their boundaries.
220///
221/// # Example
222/// ```no_run
223/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
224/// # use iced::widget::Widget;
225/// # pub type State = ();
226/// use iced::widget::container;
227///
228/// enum Message {
229/// // ...
230/// }
231///
232/// fn view(state: &State) -> impl Widget<Message> {
233/// container("This text is centered inside a rounded box!")
234/// .padding(10)
235/// .center(800)
236/// .style(container::rounded_box)
237/// }
238/// ```
239pub fn container<'a, W, Theme>(content: W) -> Container<'a, W, Theme>
240where
241 Theme: container::Catalog + 'a,
242{
243 Container::new(content)
244}
245
246/// Creates a new [`Container`] that fills all the available space
247/// and centers its contents inside.
248///
249/// This is equivalent to:
250/// ```rust,no_run
251/// # use iced_widget::core::Length::Fill;
252/// # use iced_widget::Container;
253/// # fn container<A>(x: A) -> Container<'static, ()> { unreachable!() }
254/// let center = container("Center!").center(Fill);
255/// ```
256///
257/// [`Container`]: crate::Container
258pub fn center<'a, W, Theme>(content: W) -> Container<'a, W, Theme>
259where
260 Theme: container::Catalog + 'a,
261{
262 container(content).center(Length::Fill)
263}
264
265/// Creates a new [`Container`] that fills all the available space
266/// horizontally and centers its contents inside.
267///
268/// This is equivalent to:
269/// ```rust,no_run
270/// # use iced_widget::core::Length::Fill;
271/// # use iced_widget::Container;
272/// # fn container<A>(x: A) -> Container<'static, ()> { unreachable!() }
273/// let center_x = container("Horizontal Center!").center_x(Fill);
274/// ```
275///
276/// [`Container`]: crate::Container
277pub fn center_x<'a, W, Theme>(content: W) -> Container<'a, W, Theme>
278where
279 Theme: container::Catalog + 'a,
280{
281 container(content).center_x(Length::Fill)
282}
283
284/// Creates a new [`Container`] that fills all the available space
285/// vertically and centers its contents inside.
286///
287/// This is equivalent to:
288/// ```rust,no_run
289/// # use iced_widget::core::Length::Fill;
290/// # use iced_widget::Container;
291/// # fn container<A>(x: A) -> Container<'static, ()> { unreachable!() }
292/// let center_y = container("Vertical Center!").center_y(Fill);
293/// ```
294///
295/// [`Container`]: crate::Container
296pub fn center_y<'a, W, Theme>(content: W) -> Container<'a, W, Theme>
297where
298 Theme: container::Catalog + 'a,
299{
300 container(content).center_y(Length::Fill)
301}
302
303/// Creates a new [`Container`] that fills all the available space
304/// horizontally and right-aligns its contents inside.
305///
306/// This is equivalent to:
307/// ```rust,no_run
308/// # use iced_widget::core::Length::Fill;
309/// # use iced_widget::Container;
310/// # fn container<A>(x: A) -> Container<'static, ()> { unreachable!() }
311/// let right = container("Right!").align_right(Fill);
312/// ```
313///
314/// [`Container`]: crate::Container
315pub fn right<'a, W, Theme>(content: W) -> Container<'a, W, Theme>
316where
317 Theme: container::Catalog + 'a,
318{
319 container(content).align_right(Length::Fill)
320}
321
322/// Creates a new [`Container`] that fills all the available space
323/// and aligns its contents inside to the right center.
324///
325/// This is equivalent to:
326/// ```rust,no_run
327/// # use iced_widget::core::Length::Fill;
328/// # use iced_widget::Container;
329/// # fn container<A>(x: A) -> Container<'static, ()> { unreachable!() }
330/// let right_center = container("Bottom Center!").align_right(Fill).center_y(Fill);
331/// ```
332///
333/// [`Container`]: crate::Container
334pub fn right_center<'a, W, Theme>(content: W) -> Container<'a, W, Theme>
335where
336 Theme: container::Catalog + 'a,
337{
338 container(content)
339 .align_right(Length::Fill)
340 .center_y(Length::Fill)
341}
342
343/// Creates a new [`Container`] that fills all the available space
344/// vertically and bottom-aligns its contents inside.
345///
346/// This is equivalent to:
347/// ```rust,no_run
348/// # use iced_widget::core::Length::Fill;
349/// # use iced_widget::Container;
350/// # fn container<A>(x: A) -> Container<'static, ()> { unreachable!() }
351/// let bottom = container("Bottom!").align_bottom(Fill);
352/// ```
353///
354/// [`Container`]: crate::Container
355pub fn bottom<'a, W, Theme>(content: W) -> Container<'a, W, Theme>
356where
357 Theme: container::Catalog + 'a,
358{
359 container(content).align_bottom(Length::Fill)
360}
361
362/// Creates a new [`Container`] that fills all the available space
363/// and aligns its contents inside to the bottom center.
364///
365/// This is equivalent to:
366/// ```rust,no_run
367/// # use iced_widget::core::Length::Fill;
368/// # use iced_widget::Container;
369/// # fn container<A>(x: A) -> Container<'static, ()> { unreachable!() }
370/// let bottom_center = container("Bottom Center!").center_x(Fill).align_bottom(Fill);
371/// ```
372///
373/// [`Container`]: crate::Container
374pub fn bottom_center<'a, W, Theme>(content: W) -> Container<'a, W, Theme>
375where
376 Theme: container::Catalog + 'a,
377{
378 container(content)
379 .center_x(Length::Fill)
380 .align_bottom(Length::Fill)
381}
382
383/// Creates a new [`Container`] that fills all the available space
384/// and aligns its contents inside to the bottom right corner.
385///
386/// This is equivalent to:
387/// ```rust,no_run
388/// # use iced_widget::core::Length::Fill;
389/// # use iced_widget::Container;
390/// # fn container<A>(x: A) -> Container<'static, ()> { unreachable!() }
391/// let bottom_right = container("Bottom!").align_right(Fill).align_bottom(Fill);
392/// ```
393///
394/// [`Container`]: crate::Container
395pub fn bottom_right<'a, W, Theme>(content: W) -> Container<'a, W, Theme>
396where
397 Theme: container::Catalog + 'a,
398{
399 container(content)
400 .align_right(Length::Fill)
401 .align_bottom(Length::Fill)
402}
403
404/// Creates a new [`Pin`] widget with the given content.
405///
406/// A [`Pin`] widget positions its contents at some fixed coordinates inside of its boundaries.
407///
408/// # Example
409/// ```no_run
410/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; pub use iced_widget::core::Length::Fill; }
411/// # use iced::widget::Widget;
412/// # pub type State = ();
413/// use iced::widget::pin;
414/// use iced::Fill;
415///
416/// enum Message {
417/// // ...
418/// }
419///
420/// fn view(state: &State) -> impl Widget<Message> {
421/// pin("This text is displayed at coordinates (50, 50)!")
422/// .x(50)
423/// .y(50)
424/// }
425/// ```
426pub fn pin<W>(content: W) -> Pin<W> {
427 Pin::new(content)
428}
429
430/// Creates a new [`Column`] with the given children.
431///
432/// Columns distribute their children vertically.
433///
434/// # Example
435/// ```no_run
436/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
437/// # pub type State = ();
438/// use iced::widget::{column, text, Widget};
439///
440/// enum Message {
441/// // ...
442/// }
443///
444/// fn view(state: &State) -> impl Widget<Message> {
445/// column((0..5).map(|i| text!("Item {i}")))
446/// }
447/// ```
448pub fn column<W>(children: impl IntoIterator<Item = W>) -> Column<W>
449where
450 W: Meta,
451{
452 Column::with_children(children)
453}
454
455/// Creates a new [`keyed::Column`] from an iterator of elements.
456///
457/// Keyed columns distribute content vertically while keeping continuity.
458///
459/// # Example
460/// ```no_run
461/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
462/// # use iced::widget::Widget;
463/// # pub type State = ();
464/// use iced::widget::{keyed_column, text};
465///
466/// enum Message {
467/// // ...
468/// }
469///
470/// fn view(state: &State) -> impl Widget<Message> {
471/// keyed_column((0..=100).map(|i| {
472/// (i, text!("Item {i}"))
473/// }))
474/// }
475/// ```
476pub fn keyed_column<Key, W>(children: impl IntoIterator<Item = (Key, W)>) -> keyed::Column<Key, W>
477where
478 Key: Copy + PartialEq,
479 W: Meta,
480{
481 keyed::Column::with_children(children)
482}
483
484/// Creates a new [`Row`] from an iterator.
485///
486/// Rows distribute their children horizontally.
487///
488/// # Example
489/// ```no_run
490/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
491/// # pub type State = ();
492/// use iced::widget::{row, text, Widget};
493///
494/// enum Message {
495/// // ...
496/// }
497///
498/// fn view(state: &State) -> impl Widget<Message> {
499/// row((0..5).map(|i| text!("Item {i}")))
500/// }
501/// ```
502pub fn row<W>(children: impl IntoIterator<Item = W>) -> Row<W>
503where
504 W: Meta,
505{
506 Row::with_children(children)
507}
508
509/// Creates a new [`Grid`] from an iterator.
510pub fn grid<W>(children: impl IntoIterator<Item = W>) -> Grid<W>
511where
512 W: Meta,
513{
514 Grid::with_children(children)
515}
516
517/// Creates a new [`Stack`] with the given children.
518///
519/// [`Stack`]: crate::Stack
520pub fn stack<W>(children: impl IntoIterator<Item = W>) -> Stack<W>
521where
522 W: Meta,
523{
524 Stack::with_children(children)
525}
526
527/// Wraps the given widget and captures any mouse button presses inside the bounds of
528/// the widget—effectively making it _opaque_.
529///
530/// This helper is meant to be used to mark elements in a [`Stack`] to avoid mouse
531/// events from passing through layers.
532///
533/// [`Stack`]: crate::Stack
534pub fn opaque<'a, Message, Theme, Renderer>(
535 content: impl Widget<Message, Theme, Renderer> + 'a,
536) -> impl Widget<Message, Theme, Renderer> + 'a
537where
538 Message: 'a,
539 Theme: 'a,
540 Renderer: core::Renderer + 'a,
541{
542 use crate::core::layout::{self, Layout};
543 use crate::core::mouse;
544 use crate::core::renderer;
545 use crate::core::widget::tree::{self, Tree};
546 use crate::core::{Event, Rectangle, Shell, Size};
547
548 struct Opaque<'a, Message, Theme, Renderer> {
549 content: Element<'a, Message, Theme, Renderer>,
550 }
551
552 impl<Message, Theme, Renderer> Meta for Opaque<'_, Message, Theme, Renderer> {}
553
554 impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>
555 for Opaque<'_, Message, Theme, Renderer>
556 where
557 Renderer: core::Renderer,
558 {
559 fn tag(&self) -> tree::Tag {
560 self.content.tag()
561 }
562
563 fn state(&self) -> tree::State {
564 self.content.state()
565 }
566
567 fn diff(&mut self, tree: &mut Tree) {
568 self.content.diff(tree);
569 }
570
571 fn size(&self) -> Size<Length> {
572 self.content.size()
573 }
574
575 fn layout(&mut self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits) {
576 self.content.layout(tree, renderer, limits);
577 }
578
579 fn draw(
580 &self,
581 tree: &Tree,
582 renderer: &mut Renderer,
583 theme: &Theme,
584 style: &renderer::Style,
585 layout: Layout,
586 cursor: mouse::Cursor,
587 viewport: &Rectangle,
588 ) {
589 self.content
590 .draw(tree, renderer, theme, style, layout, cursor, viewport);
591 }
592
593 fn operate(
594 &mut self,
595 tree: &mut Tree,
596 layout: Layout,
597 viewport: &Rectangle,
598 renderer: &Renderer,
599 operation: &mut dyn operation::Operation,
600 ) {
601 self.content
602 .operate(tree, layout, viewport, renderer, operation);
603 }
604
605 fn update(
606 &mut self,
607 tree: &mut Tree,
608 event: &Event,
609 layout: Layout,
610 cursor: mouse::Cursor,
611 renderer: &Renderer,
612 shell: &mut Shell<'_, Message>,
613 viewport: &Rectangle,
614 ) {
615 let is_mouse_press =
616 matches!(event, core::Event::Mouse(mouse::Event::ButtonPressed(_)));
617
618 self.content
619 .update(tree, event, layout, cursor, renderer, shell, viewport);
620
621 if is_mouse_press && cursor.is_over(layout.bounds()) {
622 shell.capture_event();
623 }
624 }
625
626 fn mouse_interaction(
627 &self,
628 state: &core::widget::Tree,
629 layout: core::Layout,
630 cursor: core::mouse::Cursor,
631 viewport: &core::Rectangle,
632 renderer: &Renderer,
633 ) -> core::mouse::Interaction {
634 let interaction = self
635 .content
636 .mouse_interaction(state, layout, cursor, viewport, renderer);
637
638 if interaction == mouse::Interaction::None && cursor.is_over(layout.bounds()) {
639 mouse::Interaction::Idle
640 } else {
641 interaction
642 }
643 }
644
645 fn overlay<'b>(
646 &'b mut self,
647 state: &'b mut core::widget::Tree,
648 layout: core::Layout,
649 renderer: &Renderer,
650 viewport: &Rectangle,
651 translation: core::Vector,
652 window: core::Size,
653 ) -> Vec<core::overlay::Element<'b, Message, Theme, Renderer>> {
654 self.content
655 .overlay(state, layout, renderer, viewport, translation, window)
656 }
657 }
658
659 Opaque {
660 content: content._boxed(),
661 }
662}
663
664/// Displays a widget on top of another one, only when the base widget is hovered.
665///
666/// This works analogously to a [`stack`], but it will only display the layer on top
667/// when the cursor is over the base. It can be useful for removing visual clutter.
668///
669/// [`stack`]: stack()
670pub fn hover<W, V>(base: W, top: V) -> crate::Hover<W, V> {
671 Hover::new(base, top)
672}
673
674/// Creates a new [`Sensor`] widget.
675///
676/// A [`Sensor`] widget can generate messages when its contents are shown,
677/// hidden, or resized.
678///
679/// It can even notify you with anticipation at a given distance!
680pub fn sensor<'a, Message, W>(content: W) -> Sensor<'a, (), Message, W> {
681 Sensor::new(content)
682}
683
684/// Creates a new [`Scrollable`] with the provided content.
685///
686/// Scrollables let users navigate an endless amount of content with a scrollbar.
687///
688/// # Example
689/// ```no_run
690/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
691/// # use iced::widget::Widget;
692/// # pub type State = ();
693/// use iced::widget::{column, scrollable, space};
694///
695/// enum Message {
696/// // ...
697/// }
698///
699/// fn view(state: &State) -> impl Widget<Message> {
700/// scrollable(column![
701/// "Scroll me!",
702/// space().height(3000),
703/// "You did it!",
704/// ])
705/// }
706/// ```
707pub fn scrollable<'a, Message, W, Theme>(content: W) -> Scrollable<'a, Message, W, Theme>
708where
709 Theme: scrollable::Catalog + 'a,
710{
711 Scrollable::new(content)
712}
713
714/// Creates a new [`Sticky`] for the provided content.
715///
716/// The contents of a [`Sticky`] will be displayed on an overlay, inside the
717/// visible bounds, whenever they would otherwise go out of view.
718///
719/// # Example
720/// ```no_run
721/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; pub use iced_widget::core::Length::Fill; }
722/// # use iced::widget::Widget;
723/// # pub type State = ();
724/// use iced::widget::{column, container, scrollable, sticky, space};
725/// use iced::Fill;
726///
727/// enum Message {
728/// // ...
729/// }
730///
731/// fn view(state: &State) -> impl Widget<Message> {
732/// scrollable(column![
733/// sticky(container("I always stay in view!").width(Fill).padding(10)),
734/// space().height(3000),
735/// ])
736/// }
737/// ```
738pub fn sticky<W>(content: W) -> Sticky<W> {
739 Sticky::new(content)
740}
741
742/// Creates a new [`Button`] with the provided content.
743///
744/// # Example
745/// ```no_run
746/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
747/// # use iced::widget::Widget;
748/// # pub type State = ();
749/// use iced::widget::button;
750///
751/// #[derive(Clone)]
752/// enum Message {
753/// ButtonPressed,
754/// }
755///
756/// fn view(state: &State) -> impl Widget<Message> {
757/// button("Press me!").on_press(Message::ButtonPressed)
758/// }
759/// ```
760pub fn button<'a, Message, W, Theme>(content: W) -> Button<'a, Message, W, Theme>
761where
762 Theme: button::Catalog + 'a,
763{
764 Button::new(content)
765}
766
767/// Creates a new [`Tooltip`] for the provided content with the given
768/// [`Widget`] and [`tooltip::Position`].
769///
770/// Tooltips display a hint of information over some element when hovered.
771///
772/// # Example
773/// ```no_run
774/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
775/// # use iced::widget::Widget;
776/// # pub type State = ();
777/// use iced::widget::{container, tooltip};
778///
779/// enum Message {
780/// // ...
781/// }
782///
783/// fn view(_state: &State) -> impl Widget<Message> {
784/// tooltip(
785/// "Hover me to display the tooltip!",
786/// container("This is the tooltip contents!")
787/// .padding(10)
788/// .style(container::rounded_box),
789/// tooltip::Position::Bottom,
790/// )
791/// }
792/// ```
793pub fn tooltip<'a, W, V, Theme>(
794 content: W,
795 tooltip: V,
796 position: tooltip::Position,
797) -> crate::Tooltip<'a, W, V, Theme>
798where
799 Theme: container::Catalog + 'a,
800{
801 Tooltip::new(content, tooltip, position)
802}
803
804/// Creates a new [`Text`] widget with the provided content.
805///
806/// # Example
807/// ```no_run
808/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
809/// # use iced::widget::Widget;
810/// # pub type State = ();
811/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::core::Theme, ()>;
812/// use iced::widget::text;
813/// use iced::color;
814///
815/// enum Message {
816/// // ...
817/// }
818///
819/// fn view(state: &State) -> impl Widget<Message> {
820/// text("Hello, this is iced!")
821/// .size(20)
822/// .color(color!(0x0000ff))
823/// }
824/// ```
825pub fn text<'a, Theme>(text: impl text::IntoFragment<'a>) -> Text<'a, Theme>
826where
827 Theme: text::Catalog + 'a,
828{
829 Text::new(text)
830}
831
832/// Creates a new [`Text`] widget that displays the provided value.
833pub fn value<'a, Theme>(value: impl ToString) -> Text<'a, Theme>
834where
835 Theme: text::Catalog + 'a,
836{
837 Text::new(value.to_string())
838}
839
840/// Creates a new [`Rich`] text widget with the provided spans.
841///
842/// [`Rich`]: text::Rich
843///
844/// # Example
845/// ```no_run
846/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::core::*; }
847/// # use iced::widget::Widget;
848/// # pub type State = ();
849/// use iced::font;
850/// use iced::widget::{rich_text, span};
851/// use iced::{color, never, Font};
852///
853/// #[derive(Debug, Clone)]
854/// enum Message {
855/// LinkClicked(&'static str),
856/// // ...
857/// }
858///
859/// fn view(state: &State) -> impl Widget<Message> {
860/// rich_text([
861/// span("I am red!").color(color!(0xff0000)),
862/// span(" "),
863/// span("And I am bold!").font(Font { weight: font::Weight::Bold, ..Font::default() }),
864/// ])
865/// .on_link_click(never)
866/// .size(20)
867/// }
868/// ```
869pub fn rich_text<'a, Link, Message, Theme>(
870 spans: impl AsRef<[text::Span<'a, Link>]> + 'a,
871) -> text::Rich<'a, Link, Message, Theme>
872where
873 Link: Clone + 'static,
874 Theme: text::Catalog + 'a,
875{
876 text::Rich::with_spans(spans)
877}
878
879/// Creates a new [`Span`] of text with the provided content.
880///
881/// A [`Span`] is a fragment of some [`Rich`] text.
882///
883/// [`Span`]: text::Span
884/// [`Rich`]: text::Rich
885///
886/// # Example
887/// ```no_run
888/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::core::*; }
889/// # use iced::widget::Widget;
890/// # pub type State = ();
891/// use iced::font;
892/// use iced::widget::{rich_text, span};
893/// use iced::{color, never, Font};
894///
895/// #[derive(Debug, Clone)]
896/// enum Message {
897/// // ...
898/// }
899///
900/// fn view(state: &State) -> impl Widget<Message> {
901/// rich_text![
902/// span("I am red!").color(color!(0xff0000)),
903/// " ",
904/// span("And I am bold!").font(Font { weight: font::Weight::Bold, ..Font::default() }),
905/// ]
906/// .on_link_click(never)
907/// .size(20)
908/// }
909/// ```
910pub fn span<'a, Link>(text: impl text::IntoFragment<'a>) -> text::Span<'a, Link> {
911 text::Span::new(text)
912}
913
914#[cfg(feature = "markdown")]
915#[doc(inline)]
916pub use crate::markdown::view as markdown;
917
918/// Creates a new [`Checkbox`].
919///
920/// # Example
921/// ```no_run
922/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
923/// # use iced::widget::Widget;
924/// #
925/// use iced::widget::checkbox;
926///
927/// struct State {
928/// is_checked: bool,
929/// }
930///
931/// enum Message {
932/// CheckboxToggled(bool),
933/// }
934///
935/// fn view(state: &State) -> impl Widget<Message> {
936/// checkbox(state.is_checked)
937/// .label("Toggle me!")
938/// .on_toggle(Message::CheckboxToggled)
939/// }
940///
941/// fn update(state: &mut State, message: Message) {
942/// match message {
943/// Message::CheckboxToggled(is_checked) => {
944/// state.is_checked = is_checked;
945/// }
946/// }
947/// }
948/// ```
949/// 
950pub fn checkbox<'a, Message, Theme, Renderer>(
951 is_checked: bool,
952) -> Checkbox<'a, Message, Theme, Renderer>
953where
954 Theme: checkbox::Catalog + 'a,
955 Renderer: core::text::Renderer,
956{
957 Checkbox::new(is_checked)
958}
959
960/// Creates a new [`Radio`].
961///
962/// Radio buttons let users choose a single option from a bunch of options.
963///
964/// # Example
965/// ```no_run
966/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
967/// # use iced::widget::Widget;
968/// #
969/// use iced::widget::{column, radio};
970///
971/// struct State {
972/// selection: Option<Choice>,
973/// }
974///
975/// #[derive(Debug, Clone, Copy)]
976/// enum Message {
977/// RadioSelected(Choice),
978/// }
979///
980/// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
981/// enum Choice {
982/// A,
983/// B,
984/// C,
985/// All,
986/// }
987///
988/// fn view(state: &State) -> impl Widget<Message> {
989/// let a = radio(
990/// "A",
991/// Choice::A,
992/// state.selection,
993/// Message::RadioSelected,
994/// );
995///
996/// let b = radio(
997/// "B",
998/// Choice::B,
999/// state.selection,
1000/// Message::RadioSelected,
1001/// );
1002///
1003/// let c = radio(
1004/// "C",
1005/// Choice::C,
1006/// state.selection,
1007/// Message::RadioSelected,
1008/// );
1009///
1010/// let all = radio(
1011/// "All of the above",
1012/// Choice::All,
1013/// state.selection,
1014/// Message::RadioSelected
1015/// );
1016///
1017/// column![a, b, c, all]
1018/// }
1019/// ```
1020pub fn radio<'a, Message, Theme, V>(
1021 label: impl Into<String>,
1022 value: V,
1023 selected: Option<V>,
1024 on_click: impl FnOnce(V) -> Message,
1025) -> Radio<'a, Message, Theme>
1026where
1027 Message: Clone,
1028 Theme: radio::Catalog + 'a,
1029 V: Copy + Eq,
1030{
1031 Radio::new(label, value, selected, on_click)
1032}
1033
1034/// Creates a new [`Toggler`].
1035///
1036/// Togglers let users make binary choices by toggling a switch.
1037///
1038/// # Example
1039/// ```no_run
1040/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1041/// # use iced::widget::Widget;
1042/// #
1043/// use iced::widget::toggler;
1044///
1045/// struct State {
1046/// is_checked: bool,
1047/// }
1048///
1049/// enum Message {
1050/// TogglerToggled(bool),
1051/// }
1052///
1053/// fn view(state: &State) -> impl Widget<Message> {
1054/// toggler(state.is_checked)
1055/// .label("Toggle me!")
1056/// .on_toggle(Message::TogglerToggled)
1057/// }
1058///
1059/// fn update(state: &mut State, message: Message) {
1060/// match message {
1061/// Message::TogglerToggled(is_checked) => {
1062/// state.is_checked = is_checked;
1063/// }
1064/// }
1065/// }
1066/// ```
1067pub fn toggler<'a, Message, Theme>(is_checked: bool) -> Toggler<'a, Message, Theme>
1068where
1069 Theme: toggler::Catalog + 'a,
1070{
1071 Toggler::new(is_checked)
1072}
1073
1074/// Creates a new [`TextInput`].
1075///
1076/// Text inputs display fields that can be filled with text.
1077///
1078/// # Example
1079/// ```no_run
1080/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1081/// # use iced::widget::Widget;
1082/// #
1083/// use iced::widget::text_input;
1084///
1085/// struct State {
1086/// content: String,
1087/// }
1088///
1089/// #[derive(Debug, Clone)]
1090/// enum Message {
1091/// ContentChanged(String)
1092/// }
1093///
1094/// fn view(state: &State) -> impl Widget<Message> {
1095/// text_input("Type something here...", &state.content)
1096/// .on_input(Message::ContentChanged)
1097/// }
1098///
1099/// fn update(state: &mut State, message: Message) {
1100/// match message {
1101/// Message::ContentChanged(content) => {
1102/// state.content = content;
1103/// }
1104/// }
1105/// }
1106/// ```
1107pub fn text_input<'a, Message, Theme>(
1108 placeholder: impl text::IntoFragment<'a>,
1109 value: impl text::IntoFragment<'a>,
1110) -> TextInput<'a, Message, Theme>
1111where
1112 Message: Clone,
1113 Theme: text_input::Catalog + 'a,
1114{
1115 TextInput::new(placeholder, value)
1116}
1117
1118/// Creates a new [`TextEditor`].
1119///
1120/// Text editors display a multi-line text input for text editing.
1121///
1122/// # Example
1123/// ```no_run
1124/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1125/// # use iced::widget::Widget;
1126/// #
1127/// use iced::widget::text_editor;
1128///
1129/// struct State {
1130/// content: text_editor::Content,
1131/// }
1132///
1133/// #[derive(Debug, Clone)]
1134/// enum Message {
1135/// Edit(text_editor::Action)
1136/// }
1137///
1138/// fn view(state: &State) -> impl Widget<Message> {
1139/// text_editor(&state.content)
1140/// .placeholder("Type something here...")
1141/// .on_action(Message::Edit)
1142/// }
1143///
1144/// fn update(state: &mut State, message: Message) {
1145/// match message {
1146/// Message::Edit(action) => {
1147/// state.content.perform(action);
1148/// }
1149/// }
1150/// }
1151/// ```
1152pub fn text_editor<'a, Message, Theme, Renderer>(
1153 content: &'a text_editor::Content<Renderer>,
1154) -> TextEditor<'a, core::text::parser::PlainText, Message, Theme, Renderer>
1155where
1156 Message: Clone,
1157 Theme: text_editor::Catalog + 'a,
1158 Renderer: core::text::Renderer,
1159{
1160 TextEditor::new(content)
1161}
1162
1163/// Creates a new [`Slider`].
1164///
1165/// Sliders let users set a value by moving an indicator.
1166///
1167/// # Example
1168/// ```no_run
1169/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1170/// # use iced::widget::Widget;
1171/// #
1172/// use iced::widget::slider;
1173///
1174/// struct State {
1175/// value: f32,
1176/// }
1177///
1178/// #[derive(Debug, Clone)]
1179/// enum Message {
1180/// ValueChanged(f32),
1181/// }
1182///
1183/// fn view(state: &State) -> impl Widget<Message> {
1184/// slider(0.0..=100.0, state.value, Message::ValueChanged)
1185/// }
1186///
1187/// fn update(state: &mut State, message: Message) {
1188/// match message {
1189/// Message::ValueChanged(value) => {
1190/// state.value = value;
1191/// }
1192/// }
1193/// }
1194/// ```
1195pub fn slider<'a, T, Message, Theme>(
1196 range: std::ops::RangeInclusive<T>,
1197 value: T,
1198 on_change: impl Fn(T) -> Message + 'a,
1199) -> Slider<'a, T, Message, Theme>
1200where
1201 T: Copy + std::cmp::PartialOrd,
1202 Message: Clone,
1203 Theme: slider::Catalog + 'a,
1204{
1205 Slider::new(range, value, on_change)
1206}
1207
1208/// Creates a new [`VerticalSlider`].
1209///
1210/// Sliders let users set a value by moving an indicator.
1211///
1212/// # Example
1213/// ```no_run
1214/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1215/// # use iced::widget::Widget;
1216/// #
1217/// use iced::widget::vertical_slider;
1218///
1219/// struct State {
1220/// value: f32,
1221/// }
1222///
1223/// #[derive(Debug, Clone)]
1224/// enum Message {
1225/// ValueChanged(f32),
1226/// }
1227///
1228/// fn view(state: &State) -> impl Widget<Message> {
1229/// vertical_slider(0.0..=100.0, state.value, Message::ValueChanged)
1230/// }
1231///
1232/// fn update(state: &mut State, message: Message) {
1233/// match message {
1234/// Message::ValueChanged(value) => {
1235/// state.value = value;
1236/// }
1237/// }
1238/// }
1239/// ```
1240pub fn vertical_slider<'a, T, Message, Theme>(
1241 range: std::ops::RangeInclusive<T>,
1242 value: T,
1243 on_change: impl Fn(T) -> Message + 'a,
1244) -> VerticalSlider<'a, T, Message, Theme>
1245where
1246 T: Copy + std::cmp::PartialOrd,
1247 Message: Clone,
1248 Theme: vertical_slider::Catalog + 'a,
1249{
1250 VerticalSlider::new(range, value, on_change)
1251}
1252
1253/// Creates a new [`PickList`].
1254///
1255/// Pick lists display a dropdown list of selectable options.
1256///
1257/// # Example
1258/// ```no_run
1259/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1260/// # use iced::widget::Widget;
1261/// #
1262/// use iced::widget::pick_list;
1263///
1264/// struct State {
1265/// favorite: Option<Fruit>,
1266/// }
1267///
1268/// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
1269/// enum Fruit {
1270/// Apple,
1271/// Orange,
1272/// Strawberry,
1273/// Tomato,
1274/// }
1275///
1276/// #[derive(Debug, Clone)]
1277/// enum Message {
1278/// FruitSelected(Fruit),
1279/// }
1280///
1281/// fn view(state: &State) -> impl Widget<Message> {
1282/// let fruits = [
1283/// Fruit::Apple,
1284/// Fruit::Orange,
1285/// Fruit::Strawberry,
1286/// Fruit::Tomato,
1287/// ];
1288///
1289/// pick_list(
1290/// state.favorite,
1291/// fruits,
1292/// Fruit::to_string,
1293/// )
1294/// .on_select(Message::FruitSelected)
1295/// .placeholder("Select your favorite fruit...")
1296/// }
1297///
1298/// fn update(state: &mut State, message: Message) {
1299/// match message {
1300/// Message::FruitSelected(fruit) => {
1301/// state.favorite = Some(fruit);
1302/// }
1303/// }
1304/// }
1305///
1306/// impl std::fmt::Display for Fruit {
1307/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1308/// f.write_str(match self {
1309/// Self::Apple => "Apple",
1310/// Self::Orange => "Orange",
1311/// Self::Strawberry => "Strawberry",
1312/// Self::Tomato => "Tomato",
1313/// })
1314/// }
1315/// }
1316/// ```
1317pub fn pick_list<'a, T, L, V, Message, Theme>(
1318 selected: Option<V>,
1319 options: L,
1320 to_string: impl Fn(&T) -> String + 'a,
1321) -> PickList<'a, T, L, V, Message, Theme>
1322where
1323 T: PartialEq + Clone + 'a,
1324 L: Borrow<[T]> + 'a,
1325 V: Borrow<T> + 'a,
1326 Message: Clone,
1327 Theme: pick_list::Catalog + overlay::menu::Catalog,
1328{
1329 PickList::new(selected, options, to_string)
1330}
1331
1332/// Creates a new [`ComboBox`].
1333///
1334/// Combo boxes display a dropdown list of searchable and selectable options.
1335///
1336/// # Example
1337/// ```no_run
1338/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1339/// # use iced::widget::Widget;
1340/// #
1341/// use iced::widget::combo_box;
1342///
1343/// struct State {
1344/// fruits: combo_box::State<Fruit>,
1345/// favorite: Option<Fruit>,
1346/// }
1347///
1348/// #[derive(Debug, Clone)]
1349/// enum Fruit {
1350/// Apple,
1351/// Orange,
1352/// Strawberry,
1353/// Tomato,
1354/// }
1355///
1356/// #[derive(Debug, Clone)]
1357/// enum Message {
1358/// FruitSelected(Fruit),
1359/// }
1360///
1361/// fn view(state: &State) -> impl Widget<Message> {
1362/// combo_box(
1363/// &state.fruits,
1364/// "Select your favorite fruit...",
1365/// state.favorite.as_ref(),
1366/// Message::FruitSelected
1367/// )
1368/// }
1369///
1370/// fn update(state: &mut State, message: Message) {
1371/// match message {
1372/// Message::FruitSelected(fruit) => {
1373/// state.favorite = Some(fruit);
1374/// }
1375/// }
1376/// }
1377///
1378/// impl std::fmt::Display for Fruit {
1379/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1380/// f.write_str(match self {
1381/// Self::Apple => "Apple",
1382/// Self::Orange => "Orange",
1383/// Self::Strawberry => "Strawberry",
1384/// Self::Tomato => "Tomato",
1385/// })
1386/// }
1387/// }
1388/// ```
1389pub fn combo_box<'a, T, Message, Theme>(
1390 state: &'a combo_box::State<T>,
1391 placeholder: impl text::IntoFragment<'a>,
1392 selection: Option<&T>,
1393 on_selected: impl Fn(T) -> Message + 'a,
1394) -> ComboBox<'a, T, Message, Theme>
1395where
1396 T: std::fmt::Display + Clone,
1397 Theme: combo_box::Catalog + 'a,
1398{
1399 ComboBox::new(state, placeholder, selection, on_selected)
1400}
1401
1402/// Creates some empty [`Space`] with no size.
1403///
1404/// This is considered the "identity" widget. It will take
1405/// no space and do nothing.
1406pub fn space() -> Space {
1407 Space::new()
1408}
1409
1410/// Creates a new [`ProgressBar`].
1411///
1412/// Progress bars visualize the progression of an extended computer operation, such as a download, file transfer, or installation.
1413///
1414/// It expects:
1415/// * an inclusive range of possible values, and
1416/// * the current value of the [`ProgressBar`].
1417///
1418/// # Example
1419/// ```no_run
1420/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1421/// # use iced::widget::Widget;
1422/// #
1423/// use iced::widget::progress_bar;
1424///
1425/// struct State {
1426/// progress: f32,
1427/// }
1428///
1429/// enum Message {
1430/// // ...
1431/// }
1432///
1433/// fn view(state: &State) -> impl Widget<Message> {
1434/// progress_bar(0.0..=100.0, state.progress)
1435/// }
1436/// ```
1437pub fn progress_bar<'a, Theme>(range: RangeInclusive<f32>, value: f32) -> ProgressBar<'a, Theme>
1438where
1439 Theme: progress_bar::Catalog + 'a,
1440{
1441 ProgressBar::new(range, value)
1442}
1443
1444/// Creates a new [`Image`].
1445///
1446/// Images display raster graphics in different formats (PNG, JPG, etc.).
1447///
1448/// [`Image`]: crate::Image
1449///
1450/// # Example
1451/// ```no_run
1452/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1453/// # use iced::widget::Widget;
1454/// # pub type State = ();
1455/// use iced::widget::image;
1456///
1457/// enum Message {
1458/// // ...
1459/// }
1460///
1461/// fn view(state: &State) -> impl Widget<Message> {
1462/// image("ferris.png")
1463/// }
1464/// ```
1465/// <img src="https://github.com/iced-rs/iced/blob/9712b319bb7a32848001b96bd84977430f14b623/examples/resources/ferris.png?raw=true" width="300">
1466#[cfg(feature = "image")]
1467pub fn image<Handle>(handle: impl Into<Handle>) -> crate::Image<Handle> {
1468 crate::Image::new(handle.into())
1469}
1470
1471/// Creates a new [`Svg`] widget from the given [`Handle`].
1472///
1473/// Svg widgets display vector graphics in your application.
1474///
1475/// [`Svg`]: crate::Svg
1476/// [`Handle`]: crate::svg::Handle
1477///
1478/// # Example
1479/// ```no_run
1480/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1481/// # use iced::widget::Widget;
1482/// # pub type State = ();
1483/// use iced::widget::svg;
1484///
1485/// enum Message {
1486/// // ...
1487/// }
1488///
1489/// fn view(state: &State) -> impl Widget<Message> {
1490/// svg("tiger.svg")
1491/// }
1492/// ```
1493#[cfg(feature = "svg")]
1494pub fn svg<'a, Theme>(handle: impl Into<core::svg::Handle>) -> crate::Svg<'a, Theme>
1495where
1496 Theme: crate::svg::Catalog,
1497{
1498 crate::Svg::new(handle)
1499}
1500
1501/// Creates an [`Element`] that displays the iced logo with the given `text_size`.
1502///
1503/// Useful for showing some love to your favorite GUI library in your "About" screen,
1504/// for instance.
1505pub fn iced<'a, Message, Theme, Renderer>(
1506 text_size: impl Into<core::Pixels>,
1507) -> impl Widget<Message, Theme, Renderer>
1508where
1509 Message: 'a,
1510 Renderer: core::text::Renderer + 'a,
1511 Theme: text::Catalog + container::Catalog + 'a,
1512 <Theme as container::Catalog>::Class<'a>: From<container::StyleFn<'a, Theme>>,
1513 <Theme as text::Catalog>::Class<'a>: From<text::StyleFn<'a, Theme>>,
1514{
1515 use crate::core::border;
1516 use crate::core::color;
1517 use crate::core::gradient;
1518 use crate::core::{Alignment, Color, Font, Radians};
1519
1520 let text_size = text_size.into();
1521
1522 row![
1523 container(
1524 text(Renderer::ICED_LOGO)
1525 .line_height(1.0)
1526 .size(text_size)
1527 .font(Renderer::ICON_FONT)
1528 .color(Color::WHITE)
1529 )
1530 .padding(text_size * 0.15)
1531 .style(move |_| container::Style {
1532 background: Some(
1533 gradient::Linear::new(Radians::PI / 4.0)
1534 .add_stop(0.0, color!(0x0033ff))
1535 .add_stop(1.0, color!(0x1177ff))
1536 .into()
1537 ),
1538 border: border::rounded(border::radius(text_size * 0.4)),
1539 ..container::Style::default()
1540 }),
1541 text("iced").size(text_size).font(Font::MONOSPACE)
1542 ]
1543 .spacing(text_size.0 / 3.0)
1544 .align_y(Alignment::Center)
1545}
1546
1547/// Creates a new [`Canvas`].
1548///
1549/// Canvases can be leveraged to draw interactive 2D graphics.
1550///
1551/// [`Canvas`]: crate::Canvas
1552///
1553/// # Example: Drawing a Simple Circle
1554/// ```no_run
1555/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1556/// # use iced::widget::Widget;
1557/// # pub type State = ();
1558/// #
1559/// use iced::mouse;
1560/// use iced::widget::canvas;
1561/// use iced::{Color, Rectangle, Renderer, Theme};
1562///
1563/// // First, we define the data we need for drawing
1564/// #[derive(Debug)]
1565/// struct Circle {
1566/// radius: f32,
1567/// }
1568///
1569/// // Then, we implement the `Program` trait
1570/// impl<Message> canvas::Program<Message> for Circle {
1571/// // No internal state
1572/// type State = ();
1573///
1574/// fn draw(
1575/// &self,
1576/// _state: &(),
1577/// renderer: &Renderer,
1578/// _theme: &Theme,
1579/// bounds: Rectangle,
1580/// _cursor: mouse::Cursor
1581/// ) -> Vec<canvas::Geometry> {
1582/// // We prepare a new `Frame`
1583/// let mut frame = canvas::Frame::new(renderer, bounds.size());
1584///
1585/// // We create a `Path` representing a simple circle
1586/// let circle = canvas::Path::circle(frame.center(), self.radius);
1587///
1588/// // And fill it with some color
1589/// frame.fill(&circle, Color::BLACK);
1590///
1591/// // Then, we produce the geometry
1592/// vec![frame.into_geometry()]
1593/// }
1594/// }
1595///
1596/// // Finally, we simply use our `Circle` to create the `Canvas`!
1597/// fn view<Message>(_state: &State) -> impl Widget<Message> {
1598/// canvas(Circle { radius: 50.0 })
1599/// }
1600/// ```
1601#[cfg(feature = "canvas")]
1602pub fn canvas<P, Message, Theme, Renderer>(program: P) -> crate::Canvas<P, Message, Theme, Renderer>
1603where
1604 Renderer: crate::graphics::geometry::Renderer,
1605 P: crate::canvas::Program<Message, Theme, Renderer>,
1606{
1607 crate::Canvas::new(program)
1608}
1609
1610/// Creates a new [`QRCode`] widget from the given [`Data`].
1611///
1612/// QR codes display information in a type of two-dimensional matrix barcode.
1613///
1614/// [`QRCode`]: crate::QRCode
1615/// [`Data`]: crate::qr_code::Data
1616///
1617/// # Example
1618/// ```no_run
1619/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1620/// # use iced::widget::Widget;
1621/// #
1622/// use iced::widget::qr_code;
1623///
1624/// struct State {
1625/// data: qr_code::Data,
1626/// }
1627///
1628/// #[derive(Debug, Clone)]
1629/// enum Message {
1630/// // ...
1631/// }
1632///
1633/// fn view(state: &State) -> impl Widget<Message> {
1634/// qr_code(&state.data)
1635/// }
1636/// ```
1637#[cfg(feature = "qr_code")]
1638pub fn qr_code<'a, Theme>(data: &'a crate::qr_code::Data) -> crate::QRCode<'a, Theme>
1639where
1640 Theme: crate::qr_code::Catalog + 'a,
1641{
1642 crate::QRCode::new(data)
1643}
1644
1645/// Creates a new [`Shader`].
1646///
1647/// [`Shader`]: crate::Shader
1648#[cfg(feature = "wgpu")]
1649pub fn shader<Message, P>(program: P) -> crate::Shader<Message, P>
1650where
1651 P: crate::shader::Program<Message>,
1652{
1653 crate::Shader::new(program)
1654}
1655
1656/// Creates a new [`MouseArea`].
1657pub fn mouse_area<'a, Message, W>(widget: W) -> MouseArea<'a, Message, W> {
1658 MouseArea::new(widget)
1659}
1660
1661/// A widget that applies any `Theme` to its contents.
1662pub fn themer<'a, Message, Theme, Renderer>(
1663 theme: Option<Theme>,
1664 content: impl Widget<Message, Theme, Renderer> + 'a,
1665) -> Themer<'a, Message, Theme, Renderer>
1666where
1667 Theme: theme::Base,
1668 Renderer: core::Renderer,
1669{
1670 Themer::new(theme, content)
1671}
1672
1673/// Creates a [`PaneGrid`] with the given [`pane_grid::State`] and view function.
1674///
1675/// Pane grids let your users split regions of your application and organize layout dynamically.
1676///
1677/// # Example
1678/// ```no_run
1679/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1680/// # use iced::widget::Widget;
1681/// #
1682/// use iced::widget::{pane_grid, text};
1683///
1684/// struct State {
1685/// panes: pane_grid::State<Pane>,
1686/// }
1687///
1688/// enum Pane {
1689/// SomePane,
1690/// AnotherKindOfPane,
1691/// }
1692///
1693/// enum Message {
1694/// PaneDragged(pane_grid::DragEvent),
1695/// PaneResized(pane_grid::ResizeEvent),
1696/// }
1697///
1698/// fn view(state: &State) -> impl Widget<Message> {
1699/// pane_grid(&state.panes, |pane, state, is_maximized| {
1700/// pane_grid::Content::new(match state {
1701/// Pane::SomePane => text("This is some pane"),
1702/// Pane::AnotherKindOfPane => text("This is another kind of pane"),
1703/// })
1704/// })
1705/// .on_drag(Message::PaneDragged)
1706/// .on_resize(10, Message::PaneResized)
1707/// }
1708/// ```
1709pub fn pane_grid<'a, T, Message, Title, W, Theme, Renderer>(
1710 state: &'a pane_grid::State<T>,
1711 view: impl Fn(
1712 pane_grid::Pane,
1713 &'a T,
1714 bool,
1715 ) -> pane_grid::Content<'a, Message, Title, W, Theme, Renderer>,
1716) -> PaneGrid<'a, Message, Title, W, Theme, Renderer>
1717where
1718 Theme: pane_grid::Catalog,
1719 Renderer: core::Renderer,
1720{
1721 PaneGrid::new(state, view)
1722}
1723
1724/// Creates a new [`Float`] widget with the given content.
1725pub fn float<'a, W, Theme>(content: W) -> Float<'a, W, Theme>
1726where
1727 Theme: float::Catalog,
1728{
1729 Float::new(content)
1730}
1731
1732/// Creates a new [`Responsive`] widget with a closure that produces its
1733/// contents.
1734///
1735/// The `view` closure will receive the maximum available space for
1736/// the [`Responsive`] during layout. You can use this [`Size`] to
1737/// conditionally build the contents.
1738pub fn responsive<'a, W>(f: impl Fn(Size) -> W + 'a) -> Responsive<'a, W> {
1739 Responsive::new(f)
1740}
1741
1742/// Creates a new [`Transition`].
1743///
1744/// The `init` closure will be used to initialize an implementor of [`Program`]. This is normally
1745/// an [`Animation`](crate::core::Animation), but you can implement [`Program`] on your own types
1746/// as well.
1747///
1748/// The `view` closure will receive the [`Program`] and the current [`Instant`], which can be used for interpolating values.
1749/// When the `value` changes, this will be called every frame, until the [`Program`] stops animating.
1750///
1751/// [`Program`]: transition::Program
1752///
1753/// # Example
1754///
1755/// Here is how you could implement a smooth progress bar:
1756///
1757/// ```
1758/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1759/// # use iced::widget::Widget;
1760/// use iced::widget::{transition, progress_bar};
1761/// use iced::Animation;
1762///
1763/// fn smooth_progress_bar<Message>(progress: f32) -> impl Widget<Message> {
1764/// transition(progress, || Animation::new(0.).quick(), |animation, now| {
1765/// progress_bar(0.0..=1.0, animation.interpolate_with(std::convert::identity, now))
1766/// })
1767/// }
1768/// ```
1769pub fn transition<'a, Message, W, P>(
1770 value: P::Value,
1771 init: impl Fn() -> P + 'a,
1772 view: impl Fn(&P, Instant) -> W + 'a,
1773) -> Transition<'a, Message, W, P>
1774where
1775 P: transition::Program,
1776{
1777 Transition::new(init, value, view)
1778}
1779
1780/// Creates a zero-sized [`Widget`] that does nothing and will be filtered out by
1781/// containers.
1782pub fn void() -> core::widget::Void {
1783 core::widget::Void
1784}
1785
1786/// Creates a new [`Lazy`] widget with the given data `Dependency` and a
1787/// closure that can turn this data into a widget tree.
1788pub fn lazy<'a, W, Dependency>(
1789 dependency: Dependency,
1790 view: impl Fn(&Dependency) -> W + 'a,
1791) -> Lazy<'a, W, Dependency>
1792where
1793 Dependency: std::hash::Hash + 'a,
1794{
1795 Lazy::new(dependency, view)
1796}