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