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