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