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