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