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