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