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