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::scrollable::{self, Scrollable};
19use crate::slider::{self, Slider};
20use crate::text::{self, Text};
21use crate::text_editor::{self, TextEditor};
22use crate::text_input::{self, TextInput};
23use crate::toggler::{self, Toggler};
24use crate::tooltip::{self, Tooltip};
25use crate::vertical_slider::{self, VerticalSlider};
26use crate::{
27 Column, Grid, MouseArea, Pin, Responsive, Row, Sensor, Space, Stack, Themer,
28};
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 children(&self) -> Vec<Tree> {
609 self.content.as_widget().children()
610 }
611
612 fn diff(&self, tree: &mut Tree) {
613 self.content.as_widget().diff(tree);
614 }
615
616 fn size(&self) -> Size<Length> {
617 self.content.as_widget().size()
618 }
619
620 fn size_hint(&self) -> Size<Length> {
621 self.content.as_widget().size_hint()
622 }
623
624 fn layout(
625 &mut self,
626 tree: &mut Tree,
627 renderer: &Renderer,
628 limits: &layout::Limits,
629 ) -> layout::Node {
630 self.content.as_widget_mut().layout(tree, renderer, limits)
631 }
632
633 fn draw(
634 &self,
635 tree: &Tree,
636 renderer: &mut Renderer,
637 theme: &Theme,
638 style: &renderer::Style,
639 layout: Layout<'_>,
640 cursor: mouse::Cursor,
641 viewport: &Rectangle,
642 ) {
643 self.content
644 .as_widget()
645 .draw(tree, renderer, theme, style, layout, cursor, viewport);
646 }
647
648 fn operate(
649 &mut self,
650 tree: &mut Tree,
651 layout: Layout<'_>,
652 renderer: &Renderer,
653 operation: &mut dyn operation::Operation,
654 ) {
655 self.content
656 .as_widget_mut()
657 .operate(tree, layout, renderer, operation);
658 }
659
660 fn update(
661 &mut self,
662 tree: &mut Tree,
663 event: &Event,
664 layout: Layout<'_>,
665 cursor: mouse::Cursor,
666 renderer: &Renderer,
667 clipboard: &mut dyn core::Clipboard,
668 shell: &mut Shell<'_, Message>,
669 viewport: &Rectangle,
670 ) {
671 let is_mouse_press = matches!(
672 event,
673 core::Event::Mouse(mouse::Event::ButtonPressed(_))
674 );
675
676 self.content.as_widget_mut().update(
677 tree, event, layout, cursor, renderer, clipboard, shell,
678 viewport,
679 );
680
681 if is_mouse_press && cursor.is_over(layout.bounds()) {
682 shell.capture_event();
683 }
684 }
685
686 fn mouse_interaction(
687 &self,
688 state: &core::widget::Tree,
689 layout: core::Layout<'_>,
690 cursor: core::mouse::Cursor,
691 viewport: &core::Rectangle,
692 renderer: &Renderer,
693 ) -> core::mouse::Interaction {
694 let interaction = self
695 .content
696 .as_widget()
697 .mouse_interaction(state, layout, cursor, viewport, renderer);
698
699 if interaction == mouse::Interaction::None
700 && cursor.is_over(layout.bounds())
701 {
702 mouse::Interaction::Idle
703 } else {
704 interaction
705 }
706 }
707
708 fn overlay<'b>(
709 &'b mut self,
710 state: &'b mut core::widget::Tree,
711 layout: core::Layout<'b>,
712 renderer: &Renderer,
713 viewport: &Rectangle,
714 translation: core::Vector,
715 ) -> Option<core::overlay::Element<'b, Message, Theme, Renderer>>
716 {
717 self.content.as_widget_mut().overlay(
718 state,
719 layout,
720 renderer,
721 viewport,
722 translation,
723 )
724 }
725 }
726
727 Element::new(Opaque {
728 content: content.into(),
729 })
730}
731
732/// Displays a widget on top of another one, only when the base widget is hovered.
733///
734/// This works analogously to a [`stack`], but it will only display the layer on top
735/// when the cursor is over the base. It can be useful for removing visual clutter.
736///
737/// [`stack`]: stack()
738pub fn hover<'a, Message, Theme, Renderer>(
739 base: impl Into<Element<'a, Message, Theme, Renderer>>,
740 top: impl Into<Element<'a, Message, Theme, Renderer>>,
741) -> Element<'a, Message, Theme, Renderer>
742where
743 Message: 'a,
744 Theme: 'a,
745 Renderer: core::Renderer + 'a,
746{
747 use crate::core::layout::{self, Layout};
748 use crate::core::mouse;
749 use crate::core::renderer;
750 use crate::core::widget::tree::{self, Tree};
751 use crate::core::{Event, Rectangle, Shell, Size};
752
753 struct Hover<'a, Message, Theme, Renderer> {
754 base: Element<'a, Message, Theme, Renderer>,
755 top: Element<'a, Message, Theme, Renderer>,
756 is_top_focused: bool,
757 is_top_overlay_active: bool,
758 is_hovered: bool,
759 }
760
761 impl<Message, Theme, Renderer> Widget<Message, Theme, Renderer>
762 for Hover<'_, Message, Theme, Renderer>
763 where
764 Renderer: core::Renderer,
765 {
766 fn tag(&self) -> tree::Tag {
767 struct Tag;
768 tree::Tag::of::<Tag>()
769 }
770
771 fn children(&self) -> Vec<Tree> {
772 vec![Tree::new(&self.base), Tree::new(&self.top)]
773 }
774
775 fn diff(&self, tree: &mut Tree) {
776 tree.diff_children(&[&self.base, &self.top]);
777 }
778
779 fn size(&self) -> Size<Length> {
780 self.base.as_widget().size()
781 }
782
783 fn size_hint(&self) -> Size<Length> {
784 self.base.as_widget().size_hint()
785 }
786
787 fn layout(
788 &mut self,
789 tree: &mut Tree,
790 renderer: &Renderer,
791 limits: &layout::Limits,
792 ) -> layout::Node {
793 let base = self.base.as_widget_mut().layout(
794 &mut tree.children[0],
795 renderer,
796 limits,
797 );
798
799 let top = self.top.as_widget_mut().layout(
800 &mut tree.children[1],
801 renderer,
802 &layout::Limits::new(Size::ZERO, base.size()),
803 );
804
805 layout::Node::with_children(base.size(), vec![base, top])
806 }
807
808 fn draw(
809 &self,
810 tree: &Tree,
811 renderer: &mut Renderer,
812 theme: &Theme,
813 style: &renderer::Style,
814 layout: Layout<'_>,
815 cursor: mouse::Cursor,
816 viewport: &Rectangle,
817 ) {
818 if let Some(bounds) = layout.bounds().intersection(viewport) {
819 let mut children = layout.children().zip(&tree.children);
820
821 let (base_layout, base_tree) = children.next().unwrap();
822
823 self.base.as_widget().draw(
824 base_tree,
825 renderer,
826 theme,
827 style,
828 base_layout,
829 cursor,
830 viewport,
831 );
832
833 if cursor.is_over(layout.bounds())
834 || self.is_top_focused
835 || self.is_top_overlay_active
836 {
837 let (top_layout, top_tree) = children.next().unwrap();
838
839 renderer.with_layer(bounds, |renderer| {
840 self.top.as_widget().draw(
841 top_tree, renderer, theme, style, top_layout,
842 cursor, viewport,
843 );
844 });
845 }
846 }
847 }
848
849 fn operate(
850 &mut self,
851 tree: &mut Tree,
852 layout: Layout<'_>,
853 renderer: &Renderer,
854 operation: &mut dyn operation::Operation,
855 ) {
856 let children = [&mut self.base, &mut self.top]
857 .into_iter()
858 .zip(layout.children().zip(&mut tree.children));
859
860 for (child, (layout, tree)) in children {
861 child
862 .as_widget_mut()
863 .operate(tree, layout, renderer, operation);
864 }
865 }
866
867 fn update(
868 &mut self,
869 tree: &mut Tree,
870 event: &Event,
871 layout: Layout<'_>,
872 cursor: mouse::Cursor,
873 renderer: &Renderer,
874 clipboard: &mut dyn core::Clipboard,
875 shell: &mut Shell<'_, Message>,
876 viewport: &Rectangle,
877 ) {
878 let mut children = layout.children().zip(&mut tree.children);
879 let (base_layout, base_tree) = children.next().unwrap();
880 let (top_layout, top_tree) = children.next().unwrap();
881
882 let is_hovered = cursor.is_over(layout.bounds());
883
884 if matches!(event, Event::Window(window::Event::RedrawRequested(_)))
885 {
886 let mut count_focused = operation::focusable::count();
887
888 self.top.as_widget_mut().operate(
889 top_tree,
890 top_layout,
891 renderer,
892 &mut operation::black_box(&mut count_focused),
893 );
894
895 self.is_top_focused = match count_focused.finish() {
896 operation::Outcome::Some(count) => count.focused.is_some(),
897 _ => false,
898 };
899
900 self.is_hovered = is_hovered;
901 } else if is_hovered != self.is_hovered {
902 shell.request_redraw();
903 }
904
905 let is_visible =
906 is_hovered || self.is_top_focused || self.is_top_overlay_active;
907
908 if matches!(
909 event,
910 Event::Mouse(
911 mouse::Event::CursorMoved { .. }
912 | mouse::Event::ButtonReleased(_)
913 )
914 ) || is_visible
915 {
916 let redraw_request = shell.redraw_request();
917
918 self.top.as_widget_mut().update(
919 top_tree, event, top_layout, cursor, renderer, clipboard,
920 shell, viewport,
921 );
922
923 // Ignore redraw requests of invisible content
924 if !is_visible {
925 Shell::replace_redraw_request(shell, redraw_request);
926 }
927
928 if shell.is_event_captured() {
929 return;
930 }
931 };
932
933 self.base.as_widget_mut().update(
934 base_tree,
935 event,
936 base_layout,
937 cursor,
938 renderer,
939 clipboard,
940 shell,
941 viewport,
942 );
943 }
944
945 fn mouse_interaction(
946 &self,
947 tree: &Tree,
948 layout: Layout<'_>,
949 cursor: mouse::Cursor,
950 viewport: &Rectangle,
951 renderer: &Renderer,
952 ) -> mouse::Interaction {
953 [&self.base, &self.top]
954 .into_iter()
955 .rev()
956 .zip(layout.children().rev().zip(tree.children.iter().rev()))
957 .map(|(child, (layout, tree))| {
958 child.as_widget().mouse_interaction(
959 tree, layout, cursor, viewport, renderer,
960 )
961 })
962 .find(|&interaction| interaction != mouse::Interaction::None)
963 .unwrap_or_default()
964 }
965
966 fn overlay<'b>(
967 &'b mut self,
968 tree: &'b mut core::widget::Tree,
969 layout: core::Layout<'b>,
970 renderer: &Renderer,
971 viewport: &Rectangle,
972 translation: core::Vector,
973 ) -> Option<core::overlay::Element<'b, Message, Theme, Renderer>>
974 {
975 let mut overlays = [&mut self.base, &mut self.top]
976 .into_iter()
977 .zip(layout.children().zip(tree.children.iter_mut()))
978 .map(|(child, (layout, tree))| {
979 child.as_widget_mut().overlay(
980 tree,
981 layout,
982 renderer,
983 viewport,
984 translation,
985 )
986 });
987
988 if let Some(base_overlay) = overlays.next()? {
989 return Some(base_overlay);
990 }
991
992 let top_overlay = overlays.next()?;
993 self.is_top_overlay_active = top_overlay.is_some();
994
995 top_overlay
996 }
997 }
998
999 Element::new(Hover {
1000 base: base.into(),
1001 top: top.into(),
1002 is_top_focused: false,
1003 is_top_overlay_active: false,
1004 is_hovered: false,
1005 })
1006}
1007
1008/// Creates a new [`Sensor`] widget.
1009///
1010/// A [`Sensor`] widget can generate messages when its contents are shown,
1011/// hidden, or resized.
1012///
1013/// It can even notify you with anticipation at a given distance!
1014pub fn sensor<'a, Message, Theme, Renderer>(
1015 content: impl Into<Element<'a, Message, Theme, Renderer>>,
1016) -> Sensor<'a, (), Message, Theme, Renderer>
1017where
1018 Renderer: core::Renderer,
1019{
1020 Sensor::new(content)
1021}
1022
1023/// Creates a new [`Scrollable`] with the provided content.
1024///
1025/// Scrollables let users navigate an endless amount of content with a scrollbar.
1026///
1027/// # Example
1028/// ```no_run
1029/// # mod iced { pub mod widget { pub use iced_widget::*; } }
1030/// # pub type State = ();
1031/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;
1032/// use iced::widget::{column, scrollable, space};
1033///
1034/// enum Message {
1035/// // ...
1036/// }
1037///
1038/// fn view(state: &State) -> Element<'_, Message> {
1039/// scrollable(column![
1040/// "Scroll me!",
1041/// space().height(3000),
1042/// "You did it!",
1043/// ]).into()
1044/// }
1045/// ```
1046pub fn scrollable<'a, Message, Theme, Renderer>(
1047 content: impl Into<Element<'a, Message, Theme, Renderer>>,
1048) -> Scrollable<'a, Message, Theme, Renderer>
1049where
1050 Theme: scrollable::Catalog + 'a,
1051 Renderer: core::text::Renderer,
1052{
1053 Scrollable::new(content)
1054}
1055
1056/// Creates a new [`Button`] with the provided content.
1057///
1058/// # Example
1059/// ```no_run
1060/// # mod iced { pub mod widget { pub use iced_widget::*; } }
1061/// # pub type State = ();
1062/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;
1063/// use iced::widget::button;
1064///
1065/// #[derive(Clone)]
1066/// enum Message {
1067/// ButtonPressed,
1068/// }
1069///
1070/// fn view(state: &State) -> Element<'_, Message> {
1071/// button("Press me!").on_press(Message::ButtonPressed).into()
1072/// }
1073/// ```
1074pub fn button<'a, Message, Theme, Renderer>(
1075 content: impl Into<Element<'a, Message, Theme, Renderer>>,
1076) -> Button<'a, Message, Theme, Renderer>
1077where
1078 Theme: button::Catalog + 'a,
1079 Renderer: core::Renderer,
1080{
1081 Button::new(content)
1082}
1083
1084/// Creates a new [`Tooltip`] for the provided content with the given
1085/// [`Element`] and [`tooltip::Position`].
1086///
1087/// Tooltips display a hint of information over some element when hovered.
1088///
1089/// # Example
1090/// ```no_run
1091/// # mod iced { pub mod widget { pub use iced_widget::*; } }
1092/// # pub type State = ();
1093/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;
1094/// use iced::widget::{container, tooltip};
1095///
1096/// enum Message {
1097/// // ...
1098/// }
1099///
1100/// fn view(_state: &State) -> Element<'_, Message> {
1101/// tooltip(
1102/// "Hover me to display the tooltip!",
1103/// container("This is the tooltip contents!")
1104/// .padding(10)
1105/// .style(container::rounded_box),
1106/// tooltip::Position::Bottom,
1107/// ).into()
1108/// }
1109/// ```
1110pub fn tooltip<'a, Message, Theme, Renderer>(
1111 content: impl Into<Element<'a, Message, Theme, Renderer>>,
1112 tooltip: impl Into<Element<'a, Message, Theme, Renderer>>,
1113 position: tooltip::Position,
1114) -> crate::Tooltip<'a, Message, Theme, Renderer>
1115where
1116 Theme: container::Catalog + 'a,
1117 Renderer: core::text::Renderer,
1118{
1119 Tooltip::new(content, tooltip, position)
1120}
1121
1122/// Creates a new [`Text`] widget with the provided content.
1123///
1124/// # Example
1125/// ```no_run
1126/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1127/// # pub type State = ();
1128/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::core::Theme, ()>;
1129/// use iced::widget::text;
1130/// use iced::color;
1131///
1132/// enum Message {
1133/// // ...
1134/// }
1135///
1136/// fn view(state: &State) -> Element<'_, Message> {
1137/// text("Hello, this is iced!")
1138/// .size(20)
1139/// .color(color!(0x0000ff))
1140/// .into()
1141/// }
1142/// ```
1143pub fn text<'a, Theme, Renderer>(
1144 text: impl text::IntoFragment<'a>,
1145) -> Text<'a, Theme, Renderer>
1146where
1147 Theme: text::Catalog + 'a,
1148 Renderer: core::text::Renderer,
1149{
1150 Text::new(text)
1151}
1152
1153/// Creates a new [`Text`] widget that displays the provided value.
1154pub fn value<'a, Theme, Renderer>(
1155 value: impl ToString,
1156) -> Text<'a, Theme, Renderer>
1157where
1158 Theme: text::Catalog + 'a,
1159 Renderer: core::text::Renderer,
1160{
1161 Text::new(value.to_string())
1162}
1163
1164/// Creates a new [`Rich`] text widget with the provided spans.
1165///
1166/// [`Rich`]: text::Rich
1167///
1168/// # Example
1169/// ```no_run
1170/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::core::*; }
1171/// # pub type State = ();
1172/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;
1173/// use iced::font;
1174/// use iced::widget::{rich_text, span};
1175/// use iced::{color, never, Font};
1176///
1177/// #[derive(Debug, Clone)]
1178/// enum Message {
1179/// LinkClicked(&'static str),
1180/// // ...
1181/// }
1182///
1183/// fn view(state: &State) -> Element<'_, Message> {
1184/// rich_text([
1185/// span("I am red!").color(color!(0xff0000)),
1186/// span(" "),
1187/// span("And I am bold!").font(Font { weight: font::Weight::Bold, ..Font::default() }),
1188/// ])
1189/// .on_link_click(never)
1190/// .size(20)
1191/// .into()
1192/// }
1193/// ```
1194pub fn rich_text<'a, Link, Message, Theme, Renderer>(
1195 spans: impl AsRef<[text::Span<'a, Link, Renderer::Font>]> + 'a,
1196) -> text::Rich<'a, Link, Message, Theme, Renderer>
1197where
1198 Link: Clone + 'static,
1199 Theme: text::Catalog + 'a,
1200 Renderer: core::text::Renderer,
1201 Renderer::Font: 'a,
1202{
1203 text::Rich::with_spans(spans)
1204}
1205
1206/// Creates a new [`Span`] of text with the provided content.
1207///
1208/// A [`Span`] is a fragment of some [`Rich`] text.
1209///
1210/// [`Span`]: text::Span
1211/// [`Rich`]: text::Rich
1212///
1213/// # Example
1214/// ```no_run
1215/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::core::*; }
1216/// # pub type State = ();
1217/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;
1218/// use iced::font;
1219/// use iced::widget::{rich_text, span};
1220/// use iced::{color, never, Font};
1221///
1222/// #[derive(Debug, Clone)]
1223/// enum Message {
1224/// // ...
1225/// }
1226///
1227/// fn view(state: &State) -> Element<'_, Message> {
1228/// rich_text![
1229/// span("I am red!").color(color!(0xff0000)),
1230/// " ",
1231/// span("And I am bold!").font(Font { weight: font::Weight::Bold, ..Font::default() }),
1232/// ]
1233/// .on_link_click(never)
1234/// .size(20)
1235/// .into()
1236/// }
1237/// ```
1238pub fn span<'a, Link, Font>(
1239 text: impl text::IntoFragment<'a>,
1240) -> text::Span<'a, Link, Font> {
1241 text::Span::new(text)
1242}
1243
1244#[cfg(feature = "markdown")]
1245#[doc(inline)]
1246pub use crate::markdown::view as markdown;
1247
1248/// Creates a new [`Checkbox`].
1249///
1250/// # Example
1251/// ```no_run
1252/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1253/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;
1254/// #
1255/// use iced::widget::checkbox;
1256///
1257/// struct State {
1258/// is_checked: bool,
1259/// }
1260///
1261/// enum Message {
1262/// CheckboxToggled(bool),
1263/// }
1264///
1265/// fn view(state: &State) -> Element<'_, Message> {
1266/// checkbox(state.is_checked)
1267/// .label("Toggle me!")
1268/// .on_toggle(Message::CheckboxToggled)
1269/// .into()
1270/// }
1271///
1272/// fn update(state: &mut State, message: Message) {
1273/// match message {
1274/// Message::CheckboxToggled(is_checked) => {
1275/// state.is_checked = is_checked;
1276/// }
1277/// }
1278/// }
1279/// ```
1280/// 
1281pub fn checkbox<'a, Message, Theme, Renderer>(
1282 is_checked: bool,
1283) -> Checkbox<'a, Message, Theme, Renderer>
1284where
1285 Theme: checkbox::Catalog + 'a,
1286 Renderer: core::text::Renderer,
1287{
1288 Checkbox::new(is_checked)
1289}
1290
1291/// Creates a new [`Radio`].
1292///
1293/// Radio buttons let users choose a single option from a bunch of options.
1294///
1295/// # Example
1296/// ```no_run
1297/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1298/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;
1299/// #
1300/// use iced::widget::{column, radio};
1301///
1302/// struct State {
1303/// selection: Option<Choice>,
1304/// }
1305///
1306/// #[derive(Debug, Clone, Copy)]
1307/// enum Message {
1308/// RadioSelected(Choice),
1309/// }
1310///
1311/// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
1312/// enum Choice {
1313/// A,
1314/// B,
1315/// C,
1316/// All,
1317/// }
1318///
1319/// fn view(state: &State) -> Element<'_, Message> {
1320/// let a = radio(
1321/// "A",
1322/// Choice::A,
1323/// state.selection,
1324/// Message::RadioSelected,
1325/// );
1326///
1327/// let b = radio(
1328/// "B",
1329/// Choice::B,
1330/// state.selection,
1331/// Message::RadioSelected,
1332/// );
1333///
1334/// let c = radio(
1335/// "C",
1336/// Choice::C,
1337/// state.selection,
1338/// Message::RadioSelected,
1339/// );
1340///
1341/// let all = radio(
1342/// "All of the above",
1343/// Choice::All,
1344/// state.selection,
1345/// Message::RadioSelected
1346/// );
1347///
1348/// column![a, b, c, all].into()
1349/// }
1350/// ```
1351pub fn radio<'a, Message, Theme, Renderer, V>(
1352 label: impl Into<String>,
1353 value: V,
1354 selected: Option<V>,
1355 on_click: impl FnOnce(V) -> Message,
1356) -> Radio<'a, Message, Theme, Renderer>
1357where
1358 Message: Clone,
1359 Theme: radio::Catalog + 'a,
1360 Renderer: core::text::Renderer,
1361 V: Copy + Eq,
1362{
1363 Radio::new(label, value, selected, on_click)
1364}
1365
1366/// Creates a new [`Toggler`].
1367///
1368/// Togglers let users make binary choices by toggling a switch.
1369///
1370/// # Example
1371/// ```no_run
1372/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1373/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;
1374/// #
1375/// use iced::widget::toggler;
1376///
1377/// struct State {
1378/// is_checked: bool,
1379/// }
1380///
1381/// enum Message {
1382/// TogglerToggled(bool),
1383/// }
1384///
1385/// fn view(state: &State) -> Element<'_, Message> {
1386/// toggler(state.is_checked)
1387/// .label("Toggle me!")
1388/// .on_toggle(Message::TogglerToggled)
1389/// .into()
1390/// }
1391///
1392/// fn update(state: &mut State, message: Message) {
1393/// match message {
1394/// Message::TogglerToggled(is_checked) => {
1395/// state.is_checked = is_checked;
1396/// }
1397/// }
1398/// }
1399/// ```
1400pub fn toggler<'a, Message, Theme, Renderer>(
1401 is_checked: bool,
1402) -> Toggler<'a, Message, Theme, Renderer>
1403where
1404 Theme: toggler::Catalog + 'a,
1405 Renderer: core::text::Renderer,
1406{
1407 Toggler::new(is_checked)
1408}
1409
1410/// Creates a new [`TextInput`].
1411///
1412/// Text inputs display fields that can be filled with text.
1413///
1414/// # Example
1415/// ```no_run
1416/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1417/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;
1418/// #
1419/// use iced::widget::text_input;
1420///
1421/// struct State {
1422/// content: String,
1423/// }
1424///
1425/// #[derive(Debug, Clone)]
1426/// enum Message {
1427/// ContentChanged(String)
1428/// }
1429///
1430/// fn view(state: &State) -> Element<'_, Message> {
1431/// text_input("Type something here...", &state.content)
1432/// .on_input(Message::ContentChanged)
1433/// .into()
1434/// }
1435///
1436/// fn update(state: &mut State, message: Message) {
1437/// match message {
1438/// Message::ContentChanged(content) => {
1439/// state.content = content;
1440/// }
1441/// }
1442/// }
1443/// ```
1444pub fn text_input<'a, Message, Theme, Renderer>(
1445 placeholder: &str,
1446 value: &str,
1447) -> TextInput<'a, Message, Theme, Renderer>
1448where
1449 Message: Clone,
1450 Theme: text_input::Catalog + 'a,
1451 Renderer: core::text::Renderer,
1452{
1453 TextInput::new(placeholder, value)
1454}
1455
1456/// Creates a new [`TextEditor`].
1457///
1458/// Text editors display a multi-line text input for text editing.
1459///
1460/// # Example
1461/// ```no_run
1462/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1463/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;
1464/// #
1465/// use iced::widget::text_editor;
1466///
1467/// struct State {
1468/// content: text_editor::Content,
1469/// }
1470///
1471/// #[derive(Debug, Clone)]
1472/// enum Message {
1473/// Edit(text_editor::Action)
1474/// }
1475///
1476/// fn view(state: &State) -> Element<'_, Message> {
1477/// text_editor(&state.content)
1478/// .placeholder("Type something here...")
1479/// .on_action(Message::Edit)
1480/// .into()
1481/// }
1482///
1483/// fn update(state: &mut State, message: Message) {
1484/// match message {
1485/// Message::Edit(action) => {
1486/// state.content.perform(action);
1487/// }
1488/// }
1489/// }
1490/// ```
1491pub fn text_editor<'a, Message, Theme, Renderer>(
1492 content: &'a text_editor::Content<Renderer>,
1493) -> TextEditor<'a, core::text::highlighter::PlainText, Message, Theme, Renderer>
1494where
1495 Message: Clone,
1496 Theme: text_editor::Catalog + 'a,
1497 Renderer: core::text::Renderer,
1498{
1499 TextEditor::new(content)
1500}
1501
1502/// Creates a new [`Slider`].
1503///
1504/// Sliders let users set a value by moving an indicator.
1505///
1506/// # Example
1507/// ```no_run
1508/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1509/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;
1510/// #
1511/// use iced::widget::slider;
1512///
1513/// struct State {
1514/// value: f32,
1515/// }
1516///
1517/// #[derive(Debug, Clone)]
1518/// enum Message {
1519/// ValueChanged(f32),
1520/// }
1521///
1522/// fn view(state: &State) -> Element<'_, Message> {
1523/// slider(0.0..=100.0, state.value, Message::ValueChanged).into()
1524/// }
1525///
1526/// fn update(state: &mut State, message: Message) {
1527/// match message {
1528/// Message::ValueChanged(value) => {
1529/// state.value = value;
1530/// }
1531/// }
1532/// }
1533/// ```
1534pub fn slider<'a, T, Message, Theme>(
1535 range: std::ops::RangeInclusive<T>,
1536 value: T,
1537 on_change: impl Fn(T) -> Message + 'a,
1538) -> Slider<'a, T, Message, Theme>
1539where
1540 T: Copy + From<u8> + std::cmp::PartialOrd,
1541 Message: Clone,
1542 Theme: slider::Catalog + 'a,
1543{
1544 Slider::new(range, value, on_change)
1545}
1546
1547/// Creates a new [`VerticalSlider`].
1548///
1549/// Sliders let users set a value by moving an indicator.
1550///
1551/// # Example
1552/// ```no_run
1553/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1554/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;
1555/// #
1556/// use iced::widget::vertical_slider;
1557///
1558/// struct State {
1559/// value: f32,
1560/// }
1561///
1562/// #[derive(Debug, Clone)]
1563/// enum Message {
1564/// ValueChanged(f32),
1565/// }
1566///
1567/// fn view(state: &State) -> Element<'_, Message> {
1568/// vertical_slider(0.0..=100.0, state.value, Message::ValueChanged).into()
1569/// }
1570///
1571/// fn update(state: &mut State, message: Message) {
1572/// match message {
1573/// Message::ValueChanged(value) => {
1574/// state.value = value;
1575/// }
1576/// }
1577/// }
1578/// ```
1579pub fn vertical_slider<'a, T, Message, Theme>(
1580 range: std::ops::RangeInclusive<T>,
1581 value: T,
1582 on_change: impl Fn(T) -> Message + 'a,
1583) -> VerticalSlider<'a, T, Message, Theme>
1584where
1585 T: Copy + From<u8> + std::cmp::PartialOrd,
1586 Message: Clone,
1587 Theme: vertical_slider::Catalog + 'a,
1588{
1589 VerticalSlider::new(range, value, on_change)
1590}
1591
1592/// Creates a new [`PickList`].
1593///
1594/// Pick lists display a dropdown list of selectable options.
1595///
1596/// # Example
1597/// ```no_run
1598/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1599/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;
1600/// #
1601/// use iced::widget::pick_list;
1602///
1603/// struct State {
1604/// favorite: Option<Fruit>,
1605/// }
1606///
1607/// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
1608/// enum Fruit {
1609/// Apple,
1610/// Orange,
1611/// Strawberry,
1612/// Tomato,
1613/// }
1614///
1615/// #[derive(Debug, Clone)]
1616/// enum Message {
1617/// FruitSelected(Fruit),
1618/// }
1619///
1620/// fn view(state: &State) -> Element<'_, Message> {
1621/// let fruits = [
1622/// Fruit::Apple,
1623/// Fruit::Orange,
1624/// Fruit::Strawberry,
1625/// Fruit::Tomato,
1626/// ];
1627///
1628/// pick_list(
1629/// fruits,
1630/// state.favorite,
1631/// Message::FruitSelected,
1632/// )
1633/// .placeholder("Select your favorite fruit...")
1634/// .into()
1635/// }
1636///
1637/// fn update(state: &mut State, message: Message) {
1638/// match message {
1639/// Message::FruitSelected(fruit) => {
1640/// state.favorite = Some(fruit);
1641/// }
1642/// }
1643/// }
1644///
1645/// impl std::fmt::Display for Fruit {
1646/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1647/// f.write_str(match self {
1648/// Self::Apple => "Apple",
1649/// Self::Orange => "Orange",
1650/// Self::Strawberry => "Strawberry",
1651/// Self::Tomato => "Tomato",
1652/// })
1653/// }
1654/// }
1655/// ```
1656pub fn pick_list<'a, T, L, V, Message, Theme, Renderer>(
1657 options: L,
1658 selected: Option<V>,
1659 on_selected: impl Fn(T) -> Message + 'a,
1660) -> PickList<'a, T, L, V, Message, Theme, Renderer>
1661where
1662 T: ToString + PartialEq + Clone + 'a,
1663 L: Borrow<[T]> + 'a,
1664 V: Borrow<T> + 'a,
1665 Message: Clone,
1666 Theme: pick_list::Catalog + overlay::menu::Catalog,
1667 Renderer: core::text::Renderer,
1668{
1669 PickList::new(options, selected, on_selected)
1670}
1671
1672/// Creates a new [`ComboBox`].
1673///
1674/// Combo boxes display a dropdown list of searchable and selectable options.
1675///
1676/// # Example
1677/// ```no_run
1678/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1679/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;
1680/// #
1681/// use iced::widget::combo_box;
1682///
1683/// struct State {
1684/// fruits: combo_box::State<Fruit>,
1685/// favorite: Option<Fruit>,
1686/// }
1687///
1688/// #[derive(Debug, Clone)]
1689/// enum Fruit {
1690/// Apple,
1691/// Orange,
1692/// Strawberry,
1693/// Tomato,
1694/// }
1695///
1696/// #[derive(Debug, Clone)]
1697/// enum Message {
1698/// FruitSelected(Fruit),
1699/// }
1700///
1701/// fn view(state: &State) -> Element<'_, Message> {
1702/// combo_box(
1703/// &state.fruits,
1704/// "Select your favorite fruit...",
1705/// state.favorite.as_ref(),
1706/// Message::FruitSelected
1707/// )
1708/// .into()
1709/// }
1710///
1711/// fn update(state: &mut State, message: Message) {
1712/// match message {
1713/// Message::FruitSelected(fruit) => {
1714/// state.favorite = Some(fruit);
1715/// }
1716/// }
1717/// }
1718///
1719/// impl std::fmt::Display for Fruit {
1720/// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1721/// f.write_str(match self {
1722/// Self::Apple => "Apple",
1723/// Self::Orange => "Orange",
1724/// Self::Strawberry => "Strawberry",
1725/// Self::Tomato => "Tomato",
1726/// })
1727/// }
1728/// }
1729/// ```
1730pub fn combo_box<'a, T, Message, Theme, Renderer>(
1731 state: &'a combo_box::State<T>,
1732 placeholder: &str,
1733 selection: Option<&T>,
1734 on_selected: impl Fn(T) -> Message + 'static,
1735) -> ComboBox<'a, T, Message, Theme, Renderer>
1736where
1737 T: std::fmt::Display + Clone,
1738 Theme: combo_box::Catalog + 'a,
1739 Renderer: core::text::Renderer,
1740{
1741 ComboBox::new(state, placeholder, selection, on_selected)
1742}
1743
1744/// Creates some empty [`Space`] with no size.
1745///
1746/// This is considered the "identity" widget. It will take
1747/// no space and do nothing.
1748pub fn space() -> Space {
1749 Space::new()
1750}
1751
1752/// Creates a new [`ProgressBar`].
1753///
1754/// Progress bars visualize the progression of an extended computer operation, such as a download, file transfer, or installation.
1755///
1756/// It expects:
1757/// * an inclusive range of possible values, and
1758/// * the current value of the [`ProgressBar`].
1759///
1760/// # Example
1761/// ```no_run
1762/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1763/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;
1764/// #
1765/// use iced::widget::progress_bar;
1766///
1767/// struct State {
1768/// progress: f32,
1769/// }
1770///
1771/// enum Message {
1772/// // ...
1773/// }
1774///
1775/// fn view(state: &State) -> Element<'_, Message> {
1776/// progress_bar(0.0..=100.0, state.progress).into()
1777/// }
1778/// ```
1779pub fn progress_bar<'a, Theme>(
1780 range: RangeInclusive<f32>,
1781 value: f32,
1782) -> ProgressBar<'a, Theme>
1783where
1784 Theme: progress_bar::Catalog + 'a,
1785{
1786 ProgressBar::new(range, value)
1787}
1788
1789/// Creates a new [`Image`].
1790///
1791/// Images display raster graphics in different formats (PNG, JPG, etc.).
1792///
1793/// [`Image`]: crate::Image
1794///
1795/// # Example
1796/// ```no_run
1797/// # mod iced { pub mod widget { pub use iced_widget::*; } }
1798/// # pub type State = ();
1799/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;
1800/// use iced::widget::image;
1801///
1802/// enum Message {
1803/// // ...
1804/// }
1805///
1806/// fn view(state: &State) -> Element<'_, Message> {
1807/// image("ferris.png").into()
1808/// }
1809/// ```
1810/// <img src="https://github.com/iced-rs/iced/blob/9712b319bb7a32848001b96bd84977430f14b623/examples/resources/ferris.png?raw=true" width="300">
1811#[cfg(feature = "image")]
1812pub fn image<Handle>(handle: impl Into<Handle>) -> crate::Image<Handle> {
1813 crate::Image::new(handle.into())
1814}
1815
1816/// Creates a new [`Svg`] widget from the given [`Handle`].
1817///
1818/// Svg widgets display vector graphics in your application.
1819///
1820/// [`Svg`]: crate::Svg
1821/// [`Handle`]: crate::svg::Handle
1822///
1823/// # Example
1824/// ```no_run
1825/// # mod iced { pub mod widget { pub use iced_widget::*; } }
1826/// # pub type State = ();
1827/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;
1828/// use iced::widget::svg;
1829///
1830/// enum Message {
1831/// // ...
1832/// }
1833///
1834/// fn view(state: &State) -> Element<'_, Message> {
1835/// svg("tiger.svg").into()
1836/// }
1837/// ```
1838#[cfg(feature = "svg")]
1839pub fn svg<'a, Theme>(
1840 handle: impl Into<core::svg::Handle>,
1841) -> crate::Svg<'a, Theme>
1842where
1843 Theme: crate::svg::Catalog,
1844{
1845 crate::Svg::new(handle)
1846}
1847
1848/// Creates an [`Element`] that displays the iced logo with the given `text_size`.
1849///
1850/// Useful for showing some love to your favorite GUI library in your "About" screen,
1851/// for instance.
1852pub fn iced<'a, Message, Theme, Renderer>(
1853 text_size: impl Into<core::Pixels>,
1854) -> Element<'a, Message, Theme, Renderer>
1855where
1856 Message: 'a,
1857 Renderer: core::Renderer + core::text::Renderer<Font = core::Font> + 'a,
1858 Theme: text::Catalog + container::Catalog + 'a,
1859 <Theme as container::Catalog>::Class<'a>:
1860 From<container::StyleFn<'a, Theme>>,
1861 <Theme as text::Catalog>::Class<'a>: From<text::StyleFn<'a, Theme>>,
1862{
1863 use crate::core::border;
1864 use crate::core::color;
1865 use crate::core::gradient;
1866 use crate::core::{Alignment, Color, Font, Radians};
1867
1868 let text_size = text_size.into();
1869
1870 row![
1871 container(
1872 text(Renderer::ICED_LOGO)
1873 .line_height(1.0)
1874 .size(text_size)
1875 .font(Renderer::ICON_FONT)
1876 .color(Color::WHITE)
1877 )
1878 .padding(text_size * 0.15)
1879 .style(move |_| container::Style {
1880 background: Some(
1881 gradient::Linear::new(Radians::PI / 4.0)
1882 .add_stop(0.0, color!(0x0033ff))
1883 .add_stop(1.0, color!(0x1177ff))
1884 .into()
1885 ),
1886 border: border::rounded(border::radius(text_size * 0.4)),
1887 ..container::Style::default()
1888 }),
1889 text("iced").size(text_size).font(Font::MONOSPACE)
1890 ]
1891 .spacing(text_size.0 / 3.0)
1892 .align_y(Alignment::Center)
1893 .into()
1894}
1895
1896/// Creates a new [`Canvas`].
1897///
1898/// Canvases can be leveraged to draw interactive 2D graphics.
1899///
1900/// [`Canvas`]: crate::Canvas
1901///
1902/// # Example: Drawing a Simple Circle
1903/// ```no_run
1904/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1905/// # pub type State = ();
1906/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;
1907/// #
1908/// use iced::mouse;
1909/// use iced::widget::canvas;
1910/// use iced::{Color, Rectangle, Renderer, Theme};
1911///
1912/// // First, we define the data we need for drawing
1913/// #[derive(Debug)]
1914/// struct Circle {
1915/// radius: f32,
1916/// }
1917///
1918/// // Then, we implement the `Program` trait
1919/// impl<Message> canvas::Program<Message> for Circle {
1920/// // No internal state
1921/// type State = ();
1922///
1923/// fn draw(
1924/// &self,
1925/// _state: &(),
1926/// renderer: &Renderer,
1927/// _theme: &Theme,
1928/// bounds: Rectangle,
1929/// _cursor: mouse::Cursor
1930/// ) -> Vec<canvas::Geometry> {
1931/// // We prepare a new `Frame`
1932/// let mut frame = canvas::Frame::new(renderer, bounds.size());
1933///
1934/// // We create a `Path` representing a simple circle
1935/// let circle = canvas::Path::circle(frame.center(), self.radius);
1936///
1937/// // And fill it with some color
1938/// frame.fill(&circle, Color::BLACK);
1939///
1940/// // Then, we produce the geometry
1941/// vec![frame.into_geometry()]
1942/// }
1943/// }
1944///
1945/// // Finally, we simply use our `Circle` to create the `Canvas`!
1946/// fn view<'a, Message: 'a>(_state: &'a State) -> Element<'a, Message> {
1947/// canvas(Circle { radius: 50.0 }).into()
1948/// }
1949/// ```
1950#[cfg(feature = "canvas")]
1951pub fn canvas<P, Message, Theme, Renderer>(
1952 program: P,
1953) -> crate::Canvas<P, Message, Theme, Renderer>
1954where
1955 Renderer: crate::graphics::geometry::Renderer,
1956 P: crate::canvas::Program<Message, Theme, Renderer>,
1957{
1958 crate::Canvas::new(program)
1959}
1960
1961/// Creates a new [`QRCode`] widget from the given [`Data`].
1962///
1963/// QR codes display information in a type of two-dimensional matrix barcode.
1964///
1965/// [`QRCode`]: crate::QRCode
1966/// [`Data`]: crate::qr_code::Data
1967///
1968/// # Example
1969/// ```no_run
1970/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
1971/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;
1972/// #
1973/// use iced::widget::qr_code;
1974///
1975/// struct State {
1976/// data: qr_code::Data,
1977/// }
1978///
1979/// #[derive(Debug, Clone)]
1980/// enum Message {
1981/// // ...
1982/// }
1983///
1984/// fn view(state: &State) -> Element<'_, Message> {
1985/// qr_code(&state.data).into()
1986/// }
1987/// ```
1988#[cfg(feature = "qr_code")]
1989pub fn qr_code<'a, Theme>(
1990 data: &'a crate::qr_code::Data,
1991) -> crate::QRCode<'a, Theme>
1992where
1993 Theme: crate::qr_code::Catalog + 'a,
1994{
1995 crate::QRCode::new(data)
1996}
1997
1998/// Creates a new [`Shader`].
1999///
2000/// [`Shader`]: crate::Shader
2001#[cfg(feature = "wgpu")]
2002pub fn shader<Message, P>(program: P) -> crate::Shader<Message, P>
2003where
2004 P: crate::shader::Program<Message>,
2005{
2006 crate::Shader::new(program)
2007}
2008
2009/// Creates a new [`MouseArea`].
2010pub fn mouse_area<'a, Message, Theme, Renderer>(
2011 widget: impl Into<Element<'a, Message, Theme, Renderer>>,
2012) -> MouseArea<'a, Message, Theme, Renderer>
2013where
2014 Renderer: core::Renderer,
2015{
2016 MouseArea::new(widget)
2017}
2018
2019/// A widget that applies any `Theme` to its contents.
2020pub fn themer<'a, Message, Theme, Renderer>(
2021 theme: Option<Theme>,
2022 content: impl Into<Element<'a, Message, Theme, Renderer>>,
2023) -> Themer<'a, Message, Theme, Renderer>
2024where
2025 Theme: theme::Base,
2026 Renderer: core::Renderer,
2027{
2028 Themer::new(theme, content)
2029}
2030
2031/// Creates a [`PaneGrid`] with the given [`pane_grid::State`] and view function.
2032///
2033/// Pane grids let your users split regions of your application and organize layout dynamically.
2034///
2035/// # Example
2036/// ```no_run
2037/// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; }
2038/// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>;
2039/// #
2040/// use iced::widget::{pane_grid, text};
2041///
2042/// struct State {
2043/// panes: pane_grid::State<Pane>,
2044/// }
2045///
2046/// enum Pane {
2047/// SomePane,
2048/// AnotherKindOfPane,
2049/// }
2050///
2051/// enum Message {
2052/// PaneDragged(pane_grid::DragEvent),
2053/// PaneResized(pane_grid::ResizeEvent),
2054/// }
2055///
2056/// fn view(state: &State) -> Element<'_, Message> {
2057/// pane_grid(&state.panes, |pane, state, is_maximized| {
2058/// pane_grid::Content::new(match state {
2059/// Pane::SomePane => text("This is some pane"),
2060/// Pane::AnotherKindOfPane => text("This is another kind of pane"),
2061/// })
2062/// })
2063/// .on_drag(Message::PaneDragged)
2064/// .on_resize(10, Message::PaneResized)
2065/// .into()
2066/// }
2067/// ```
2068pub fn pane_grid<'a, T, Message, Theme, Renderer>(
2069 state: &'a pane_grid::State<T>,
2070 view: impl Fn(
2071 pane_grid::Pane,
2072 &'a T,
2073 bool,
2074 ) -> pane_grid::Content<'a, Message, Theme, Renderer>,
2075) -> PaneGrid<'a, Message, Theme, Renderer>
2076where
2077 Theme: pane_grid::Catalog,
2078 Renderer: core::Renderer,
2079{
2080 PaneGrid::new(state, view)
2081}
2082
2083/// Creates a new [`Float`] widget with the given content.
2084pub fn float<'a, Message, Theme, Renderer>(
2085 content: impl Into<Element<'a, Message, Theme, Renderer>>,
2086) -> Float<'a, Message, Theme, Renderer>
2087where
2088 Theme: float::Catalog,
2089 Renderer: core::Renderer,
2090{
2091 Float::new(content)
2092}
2093
2094/// Creates a new [`Responsive`] widget with a closure that produces its
2095/// contents.
2096///
2097/// The `view` closure will receive the maximum available space for
2098/// the [`Responsive`] during layout. You can use this [`Size`] to
2099/// conditionally build the contents.
2100pub fn responsive<'a, Message, Theme, Renderer>(
2101 f: impl Fn(Size) -> Element<'a, Message, Theme, Renderer> + 'a,
2102) -> Responsive<'a, Message, Theme, Renderer>
2103where
2104 Renderer: core::Renderer,
2105{
2106 Responsive::new(f)
2107}