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