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