//! Helper functions to create pure widgets. use crate::button::{self, Button}; use crate::checkbox::{self, Checkbox}; use crate::combo_box::{self, ComboBox}; use crate::container::{self, Container}; use crate::core; use crate::core::widget::operation::{self, Operation}; use crate::core::window; use crate::core::{Element, Length, Pixels, Widget}; use crate::keyed; use crate::overlay; use crate::pane_grid::{self, PaneGrid}; use crate::pick_list::{self, PickList}; use crate::progress_bar::{self, ProgressBar}; use crate::radio::{self, Radio}; use crate::rule::{self, Rule}; use crate::runtime::Action; use crate::runtime::task::{self, Task}; use crate::scrollable::{self, Scrollable}; use crate::slider::{self, Slider}; use crate::text::{self, Text}; use crate::text_editor::{self, TextEditor}; use crate::text_input::{self, TextInput}; use crate::toggler::{self, Toggler}; use crate::tooltip::{self, Tooltip}; use crate::vertical_slider::{self, VerticalSlider}; use crate::{Column, MouseArea, Pin, Pop, Row, Space, Stack, Themer}; use std::borrow::Borrow; use std::ops::RangeInclusive; /// Creates a [`Column`] with the given children. /// /// Columns distribute their children vertically. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } } /// # pub type State = (); /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// use iced::widget::{button, column}; /// /// #[derive(Debug, Clone)] /// enum Message { /// // ... /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// column![ /// "I am on top!", /// button("I am in the center!"), /// "I am below.", /// ].into() /// } /// ``` #[macro_export] macro_rules! column { () => ( $crate::Column::new() ); ($($x:expr),+ $(,)?) => ( $crate::Column::with_children([$($crate::core::Element::from($x)),+]) ); } /// Creates a [`Row`] with the given children. /// /// Rows distribute their children horizontally. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } } /// # pub type State = (); /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// use iced::widget::{button, row}; /// /// #[derive(Debug, Clone)] /// enum Message { /// // ... /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// row![ /// "I am to the left!", /// button("I am in the middle!"), /// "I am to the right!", /// ].into() /// } /// ``` #[macro_export] macro_rules! row { () => ( $crate::Row::new() ); ($($x:expr),+ $(,)?) => ( $crate::Row::with_children([$($crate::core::Element::from($x)),+]) ); } /// Creates a [`Stack`] with the given children. /// /// [`Stack`]: crate::Stack #[macro_export] macro_rules! stack { () => ( $crate::Stack::new() ); ($($x:expr),+ $(,)?) => ( $crate::Stack::with_children([$($crate::core::Element::from($x)),+]) ); } /// Creates a new [`Text`] widget with the provided content. /// /// [`Text`]: core::widget::Text /// /// This macro uses the same syntax as [`format!`], but creates a new [`Text`] widget instead. /// /// See [the formatting documentation in `std::fmt`](std::fmt) /// for details of the macro argument syntax. /// /// # Examples /// /// ```no_run /// # mod iced { /// # pub mod widget { /// # macro_rules! text { /// # ($($arg:tt)*) => {unimplemented!()} /// # } /// # pub(crate) use text; /// # } /// # } /// # pub type State = (); /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::core::Theme, ()>; /// use iced::widget::text; /// /// enum Message { /// // ... /// } /// /// fn view(_state: &State) -> Element { /// let simple = text!("Hello, world!"); /// /// let keyword = text!("Hello, {}", "world!"); /// /// let planet = "Earth"; /// let local_variable = text!("Hello, {planet}!"); /// // ... /// # unimplemented!() /// } /// ``` #[macro_export] macro_rules! text { ($($arg:tt)*) => { $crate::Text::new(format!($($arg)*)) }; } /// Creates some [`Rich`] text with the given spans. /// /// [`Rich`]: text::Rich /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::core::*; } /// # pub type State = (); /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// use iced::font; /// use iced::widget::{rich_text, span}; /// use iced::{color, never, Font}; /// /// #[derive(Debug, Clone)] /// enum Message { /// // ... /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// rich_text![ /// span("I am red!").color(color!(0xff0000)), /// span(" "), /// span("And I am bold!").font(Font { weight: font::Weight::Bold, ..Font::default() }), /// ] /// .on_link_click(never) /// .size(20) /// .into() /// } /// ``` #[macro_export] macro_rules! rich_text { () => ( $crate::text::Rich::new() ); ($($x:expr),+ $(,)?) => ( $crate::text::Rich::from_iter([$($crate::text::Span::from($x)),+]) ); } /// Creates a new [`Container`] with the provided content. /// /// Containers let you align a widget inside their boundaries. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } } /// # pub type State = (); /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// use iced::widget::container; /// /// enum Message { /// // ... /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// container("This text is centered inside a rounded box!") /// .padding(10) /// .center(800) /// .style(container::rounded_box) /// .into() /// } /// ``` pub fn container<'a, Message, Theme, Renderer>( content: impl Into>, ) -> Container<'a, Message, Theme, Renderer> where Theme: container::Catalog + 'a, Renderer: core::Renderer, { Container::new(content) } /// Creates a new [`Container`] that fills all the available space /// and centers its contents inside. /// /// This is equivalent to: /// ```rust,no_run /// # use iced_widget::core::Length::Fill; /// # use iced_widget::Container; /// # fn container(x: A) -> Container<'static, ()> { unreachable!() } /// let center = container("Center!").center(Fill); /// ``` /// /// [`Container`]: crate::Container pub fn center<'a, Message, Theme, Renderer>( content: impl Into>, ) -> Container<'a, Message, Theme, Renderer> where Theme: container::Catalog + 'a, Renderer: core::Renderer, { container(content).center(Length::Fill) } /// Creates a new [`Container`] that fills all the available space /// horizontally and centers its contents inside. /// /// This is equivalent to: /// ```rust,no_run /// # use iced_widget::core::Length::Fill; /// # use iced_widget::Container; /// # fn container(x: A) -> Container<'static, ()> { unreachable!() } /// let center_x = container("Horizontal Center!").center_x(Fill); /// ``` /// /// [`Container`]: crate::Container pub fn center_x<'a, Message, Theme, Renderer>( content: impl Into>, ) -> Container<'a, Message, Theme, Renderer> where Theme: container::Catalog + 'a, Renderer: core::Renderer, { container(content).center_x(Length::Fill) } /// Creates a new [`Container`] that fills all the available space /// vertically and centers its contents inside. /// /// This is equivalent to: /// ```rust,no_run /// # use iced_widget::core::Length::Fill; /// # use iced_widget::Container; /// # fn container(x: A) -> Container<'static, ()> { unreachable!() } /// let center_y = container("Vertical Center!").center_y(Fill); /// ``` /// /// [`Container`]: crate::Container pub fn center_y<'a, Message, Theme, Renderer>( content: impl Into>, ) -> Container<'a, Message, Theme, Renderer> where Theme: container::Catalog + 'a, Renderer: core::Renderer, { container(content).center_y(Length::Fill) } /// Creates a new [`Container`] that fills all the available space /// horizontally and right-aligns its contents inside. /// /// This is equivalent to: /// ```rust,no_run /// # use iced_widget::core::Length::Fill; /// # use iced_widget::Container; /// # fn container(x: A) -> Container<'static, ()> { unreachable!() } /// let right = container("Right!").align_right(Fill); /// ``` /// /// [`Container`]: crate::Container pub fn right<'a, Message, Theme, Renderer>( content: impl Into>, ) -> Container<'a, Message, Theme, Renderer> where Theme: container::Catalog + 'a, Renderer: core::Renderer, { container(content).align_right(Length::Fill) } /// Creates a new [`Container`] that fills all the available space /// and aligns its contents inside to the right center. /// /// This is equivalent to: /// ```rust,no_run /// # use iced_widget::core::Length::Fill; /// # use iced_widget::Container; /// # fn container(x: A) -> Container<'static, ()> { unreachable!() } /// let right_center = container("Bottom Center!").align_right(Fill).center_y(Fill); /// ``` /// /// [`Container`]: crate::Container pub fn right_center<'a, Message, Theme, Renderer>( content: impl Into>, ) -> Container<'a, Message, Theme, Renderer> where Theme: container::Catalog + 'a, Renderer: core::Renderer, { container(content) .align_right(Length::Fill) .center_y(Length::Fill) } /// Creates a new [`Container`] that fills all the available space /// vertically and bottom-aligns its contents inside. /// /// This is equivalent to: /// ```rust,no_run /// # use iced_widget::core::Length::Fill; /// # use iced_widget::Container; /// # fn container(x: A) -> Container<'static, ()> { unreachable!() } /// let bottom = container("Bottom!").align_bottom(Fill); /// ``` /// /// [`Container`]: crate::Container pub fn bottom<'a, Message, Theme, Renderer>( content: impl Into>, ) -> Container<'a, Message, Theme, Renderer> where Theme: container::Catalog + 'a, Renderer: core::Renderer, { container(content).align_bottom(Length::Fill) } /// Creates a new [`Container`] that fills all the available space /// and aligns its contents inside to the bottom center. /// /// This is equivalent to: /// ```rust,no_run /// # use iced_widget::core::Length::Fill; /// # use iced_widget::Container; /// # fn container(x: A) -> Container<'static, ()> { unreachable!() } /// let bottom_center = container("Bottom Center!").center_x(Fill).align_bottom(Fill); /// ``` /// /// [`Container`]: crate::Container pub fn bottom_center<'a, Message, Theme, Renderer>( content: impl Into>, ) -> Container<'a, Message, Theme, Renderer> where Theme: container::Catalog + 'a, Renderer: core::Renderer, { container(content) .center_x(Length::Fill) .align_bottom(Length::Fill) } /// Creates a new [`Container`] that fills all the available space /// and aligns its contents inside to the bottom right corner. /// /// This is equivalent to: /// ```rust,no_run /// # use iced_widget::core::Length::Fill; /// # use iced_widget::Container; /// # fn container(x: A) -> Container<'static, ()> { unreachable!() } /// let bottom_right = container("Bottom!").align_right(Fill).align_bottom(Fill); /// ``` /// /// [`Container`]: crate::Container pub fn bottom_right<'a, Message, Theme, Renderer>( content: impl Into>, ) -> Container<'a, Message, Theme, Renderer> where Theme: container::Catalog + 'a, Renderer: core::Renderer, { container(content) .align_right(Length::Fill) .align_bottom(Length::Fill) } /// Creates a new [`Pin`] widget with the given content. /// /// A [`Pin`] widget positions its contents at some fixed coordinates inside of its boundaries. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::core::Length::Fill; } /// # pub type State = (); /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// use iced::widget::pin; /// use iced::Fill; /// /// enum Message { /// // ... /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// pin("This text is displayed at coordinates (50, 50)!") /// .x(50) /// .y(50) /// .into() /// } /// ``` pub fn pin<'a, Message, Theme, Renderer>( content: impl Into>, ) -> Pin<'a, Message, Theme, Renderer> where Renderer: core::Renderer, { Pin::new(content) } /// Creates a new [`Column`] with the given children. /// /// Columns distribute their children vertically. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } } /// # pub type State = (); /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// use iced::widget::{column, text}; /// /// enum Message { /// // ... /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// column((0..5).map(|i| text!("Item {i}").into())).into() /// } /// ``` pub fn column<'a, Message, Theme, Renderer>( children: impl IntoIterator>, ) -> Column<'a, Message, Theme, Renderer> where Renderer: core::Renderer, { Column::with_children(children) } /// Creates a new [`keyed::Column`] from an iterator of elements. /// /// Keyed columns distribute content vertically while keeping continuity. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } } /// # pub type State = (); /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// use iced::widget::{keyed_column, text}; /// /// enum Message { /// // ... /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// keyed_column((0..=100).map(|i| { /// (i, text!("Item {i}").into()) /// })).into() /// } /// ``` pub fn keyed_column<'a, Key, Message, Theme, Renderer>( children: impl IntoIterator)>, ) -> keyed::Column<'a, Key, Message, Theme, Renderer> where Key: Copy + PartialEq, Renderer: core::Renderer, { keyed::Column::with_children(children) } /// Creates a new [`Row`] from an iterator. /// /// Rows distribute their children horizontally. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } } /// # pub type State = (); /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// use iced::widget::{row, text}; /// /// enum Message { /// // ... /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// row((0..5).map(|i| text!("Item {i}").into())).into() /// } /// ``` pub fn row<'a, Message, Theme, Renderer>( children: impl IntoIterator>, ) -> Row<'a, Message, Theme, Renderer> where Renderer: core::Renderer, { Row::with_children(children) } /// Creates a new [`Stack`] with the given children. /// /// [`Stack`]: crate::Stack pub fn stack<'a, Message, Theme, Renderer>( children: impl IntoIterator>, ) -> Stack<'a, Message, Theme, Renderer> where Renderer: core::Renderer, { Stack::with_children(children) } /// Wraps the given widget and captures any mouse button presses inside the bounds of /// the widget—effectively making it _opaque_. /// /// This helper is meant to be used to mark elements in a [`Stack`] to avoid mouse /// events from passing through layers. /// /// [`Stack`]: crate::Stack pub fn opaque<'a, Message, Theme, Renderer>( content: impl Into>, ) -> Element<'a, Message, Theme, Renderer> where Message: 'a, Theme: 'a, Renderer: core::Renderer + 'a, { use crate::core::layout::{self, Layout}; use crate::core::mouse; use crate::core::renderer; use crate::core::widget::tree::{self, Tree}; use crate::core::{Event, Rectangle, Shell, Size}; struct Opaque<'a, Message, Theme, Renderer> { content: Element<'a, Message, Theme, Renderer>, } impl Widget for Opaque<'_, Message, Theme, Renderer> where Renderer: core::Renderer, { fn tag(&self) -> tree::Tag { self.content.as_widget().tag() } fn state(&self) -> tree::State { self.content.as_widget().state() } fn children(&self) -> Vec { self.content.as_widget().children() } fn diff(&self, tree: &mut Tree) { self.content.as_widget().diff(tree); } fn size(&self) -> Size { self.content.as_widget().size() } fn size_hint(&self) -> Size { self.content.as_widget().size_hint() } fn layout( &self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits, ) -> layout::Node { self.content.as_widget().layout(tree, renderer, limits) } fn draw( &self, tree: &Tree, renderer: &mut Renderer, theme: &Theme, style: &renderer::Style, layout: Layout<'_>, cursor: mouse::Cursor, viewport: &Rectangle, ) { self.content .as_widget() .draw(tree, renderer, theme, style, layout, cursor, viewport); } fn operate( &self, state: &mut Tree, layout: Layout<'_>, renderer: &Renderer, operation: &mut dyn operation::Operation, ) { self.content .as_widget() .operate(state, layout, renderer, operation); } fn update( &mut self, state: &mut Tree, event: &Event, layout: Layout<'_>, cursor: mouse::Cursor, renderer: &Renderer, clipboard: &mut dyn core::Clipboard, shell: &mut Shell<'_, Message>, viewport: &Rectangle, ) { let is_mouse_press = matches!( event, core::Event::Mouse(mouse::Event::ButtonPressed(_)) ); self.content.as_widget_mut().update( state, event, layout, cursor, renderer, clipboard, shell, viewport, ); if is_mouse_press && cursor.is_over(layout.bounds()) { shell.capture_event(); } } fn mouse_interaction( &self, state: &core::widget::Tree, layout: core::Layout<'_>, cursor: core::mouse::Cursor, viewport: &core::Rectangle, renderer: &Renderer, ) -> core::mouse::Interaction { let interaction = self .content .as_widget() .mouse_interaction(state, layout, cursor, viewport, renderer); if interaction == mouse::Interaction::None && cursor.is_over(layout.bounds()) { mouse::Interaction::Idle } else { interaction } } fn overlay<'b>( &'b mut self, state: &'b mut core::widget::Tree, layout: core::Layout<'_>, renderer: &Renderer, translation: core::Vector, ) -> Option> { self.content.as_widget_mut().overlay( state, layout, renderer, translation, ) } } Element::new(Opaque { content: content.into(), }) } /// Displays a widget on top of another one, only when the base widget is hovered. /// /// This works analogously to a [`stack`], but it will only display the layer on top /// when the cursor is over the base. It can be useful for removing visual clutter. /// /// [`stack`]: stack() pub fn hover<'a, Message, Theme, Renderer>( base: impl Into>, top: impl Into>, ) -> Element<'a, Message, Theme, Renderer> where Message: 'a, Theme: 'a, Renderer: core::Renderer + 'a, { use crate::core::layout::{self, Layout}; use crate::core::mouse; use crate::core::renderer; use crate::core::widget::tree::{self, Tree}; use crate::core::{Event, Rectangle, Shell, Size}; struct Hover<'a, Message, Theme, Renderer> { base: Element<'a, Message, Theme, Renderer>, top: Element<'a, Message, Theme, Renderer>, is_top_focused: bool, is_top_overlay_active: bool, is_hovered: bool, } impl Widget for Hover<'_, Message, Theme, Renderer> where Renderer: core::Renderer, { fn tag(&self) -> tree::Tag { struct Tag; tree::Tag::of::() } fn children(&self) -> Vec { vec![Tree::new(&self.base), Tree::new(&self.top)] } fn diff(&self, tree: &mut Tree) { tree.diff_children(&[&self.base, &self.top]); } fn size(&self) -> Size { self.base.as_widget().size() } fn size_hint(&self) -> Size { self.base.as_widget().size_hint() } fn layout( &self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits, ) -> layout::Node { let base = self.base.as_widget().layout( &mut tree.children[0], renderer, limits, ); let top = self.top.as_widget().layout( &mut tree.children[1], renderer, &layout::Limits::new(Size::ZERO, base.size()), ); layout::Node::with_children(base.size(), vec![base, top]) } fn draw( &self, tree: &Tree, renderer: &mut Renderer, theme: &Theme, style: &renderer::Style, layout: Layout<'_>, cursor: mouse::Cursor, viewport: &Rectangle, ) { if let Some(bounds) = layout.bounds().intersection(viewport) { let mut children = layout.children().zip(&tree.children); let (base_layout, base_tree) = children.next().unwrap(); self.base.as_widget().draw( base_tree, renderer, theme, style, base_layout, cursor, viewport, ); if cursor.is_over(layout.bounds()) || self.is_top_focused || self.is_top_overlay_active { let (top_layout, top_tree) = children.next().unwrap(); renderer.with_layer(bounds, |renderer| { self.top.as_widget().draw( top_tree, renderer, theme, style, top_layout, cursor, viewport, ); }); } } } fn operate( &self, tree: &mut Tree, layout: Layout<'_>, renderer: &Renderer, operation: &mut dyn operation::Operation, ) { let children = [&self.base, &self.top] .into_iter() .zip(layout.children().zip(&mut tree.children)); for (child, (layout, tree)) in children { child.as_widget().operate(tree, layout, renderer, operation); } } fn update( &mut self, tree: &mut Tree, event: &Event, layout: Layout<'_>, cursor: mouse::Cursor, renderer: &Renderer, clipboard: &mut dyn core::Clipboard, shell: &mut Shell<'_, Message>, viewport: &Rectangle, ) { let mut children = layout.children().zip(&mut tree.children); let (base_layout, base_tree) = children.next().unwrap(); let (top_layout, top_tree) = children.next().unwrap(); let is_hovered = cursor.is_over(layout.bounds()); if matches!(event, Event::Window(window::Event::RedrawRequested(_))) { let mut count_focused = operation::focusable::count(); self.top.as_widget_mut().operate( top_tree, top_layout, renderer, &mut operation::black_box(&mut count_focused), ); self.is_top_focused = match count_focused.finish() { operation::Outcome::Some(count) => count.focused.is_some(), _ => false, }; self.is_hovered = is_hovered; } else if is_hovered != self.is_hovered { shell.request_redraw(); } let is_visible = is_hovered || self.is_top_focused || self.is_top_overlay_active; if matches!( event, Event::Mouse( mouse::Event::CursorMoved { .. } | mouse::Event::ButtonReleased(_) ) ) || is_visible { let redraw_request = shell.redraw_request(); self.top.as_widget_mut().update( top_tree, event, top_layout, cursor, renderer, clipboard, shell, viewport, ); // Ignore redraw requests of invisible content if !is_visible { Shell::replace_redraw_request(shell, redraw_request); } }; if shell.is_event_captured() { return; } self.base.as_widget_mut().update( base_tree, event, base_layout, cursor, renderer, clipboard, shell, viewport, ); } fn mouse_interaction( &self, tree: &Tree, layout: Layout<'_>, cursor: mouse::Cursor, viewport: &Rectangle, renderer: &Renderer, ) -> mouse::Interaction { [&self.base, &self.top] .into_iter() .rev() .zip(layout.children().rev().zip(tree.children.iter().rev())) .map(|(child, (layout, tree))| { child.as_widget().mouse_interaction( tree, layout, cursor, viewport, renderer, ) }) .find(|&interaction| interaction != mouse::Interaction::None) .unwrap_or_default() } fn overlay<'b>( &'b mut self, tree: &'b mut core::widget::Tree, layout: core::Layout<'_>, renderer: &Renderer, translation: core::Vector, ) -> Option> { let mut overlays = [&mut self.base, &mut self.top] .into_iter() .zip(layout.children().zip(tree.children.iter_mut())) .map(|(child, (layout, tree))| { child.as_widget_mut().overlay( tree, layout, renderer, translation, ) }); if let Some(base_overlay) = overlays.next()? { return Some(base_overlay); } let top_overlay = overlays.next()?; self.is_top_overlay_active = top_overlay.is_some(); top_overlay } } Element::new(Hover { base: base.into(), top: top.into(), is_top_focused: false, is_top_overlay_active: false, is_hovered: false, }) } /// Creates a new [`Pop`] widget. /// /// A [`Pop`] widget can generate messages when it pops in and out of view. /// It can even notify you with anticipation at a given distance! pub fn pop<'a, Message, Theme, Renderer>( content: impl Into>, ) -> Pop<'a, Message, Theme, Renderer> where Renderer: core::Renderer, Message: Clone, { Pop::new(content) } /// Creates a new [`Scrollable`] with the provided content. /// /// Scrollables let users navigate an endless amount of content with a scrollbar. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } } /// # pub type State = (); /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// use iced::widget::{column, scrollable, vertical_space}; /// /// enum Message { /// // ... /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// scrollable(column![ /// "Scroll me!", /// vertical_space().height(3000), /// "You did it!", /// ]).into() /// } /// ``` pub fn scrollable<'a, Message, Theme, Renderer>( content: impl Into>, ) -> Scrollable<'a, Message, Theme, Renderer> where Theme: scrollable::Catalog + 'a, Renderer: core::Renderer, { Scrollable::new(content) } /// Creates a new [`Button`] with the provided content. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } } /// # pub type State = (); /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// use iced::widget::button; /// /// #[derive(Clone)] /// enum Message { /// ButtonPressed, /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// button("Press me!").on_press(Message::ButtonPressed).into() /// } /// ``` pub fn button<'a, Message, Theme, Renderer>( content: impl Into>, ) -> Button<'a, Message, Theme, Renderer> where Theme: button::Catalog + 'a, Renderer: core::Renderer, { Button::new(content) } /// Creates a new [`Tooltip`] for the provided content with the given /// [`Element`] and [`tooltip::Position`]. /// /// Tooltips display a hint of information over some element when hovered. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } } /// # pub type State = (); /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// use iced::widget::{container, tooltip}; /// /// enum Message { /// // ... /// } /// /// fn view(_state: &State) -> Element<'_, Message> { /// tooltip( /// "Hover me to display the tooltip!", /// container("This is the tooltip contents!") /// .padding(10) /// .style(container::rounded_box), /// tooltip::Position::Bottom, /// ).into() /// } /// ``` pub fn tooltip<'a, Message, Theme, Renderer>( content: impl Into>, tooltip: impl Into>, position: tooltip::Position, ) -> crate::Tooltip<'a, Message, Theme, Renderer> where Theme: container::Catalog + 'a, Renderer: core::text::Renderer, { Tooltip::new(content, tooltip, position) } /// Creates a new [`Text`] widget with the provided content. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } /// # pub type State = (); /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::core::Theme, ()>; /// use iced::widget::text; /// use iced::color; /// /// enum Message { /// // ... /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// text("Hello, this is iced!") /// .size(20) /// .color(color!(0x0000ff)) /// .into() /// } /// ``` pub fn text<'a, Theme, Renderer>( text: impl text::IntoFragment<'a>, ) -> Text<'a, Theme, Renderer> where Theme: text::Catalog + 'a, Renderer: core::text::Renderer, { Text::new(text) } /// Creates a new [`Text`] widget that displays the provided value. pub fn value<'a, Theme, Renderer>( value: impl ToString, ) -> Text<'a, Theme, Renderer> where Theme: text::Catalog + 'a, Renderer: core::text::Renderer, { Text::new(value.to_string()) } /// Creates a new [`Rich`] text widget with the provided spans. /// /// [`Rich`]: text::Rich /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::core::*; } /// # pub type State = (); /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// use iced::font; /// use iced::widget::{rich_text, span}; /// use iced::{color, never, Font}; /// /// #[derive(Debug, Clone)] /// enum Message { /// LinkClicked(&'static str), /// // ... /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// rich_text([ /// span("I am red!").color(color!(0xff0000)), /// span(" "), /// span("And I am bold!").font(Font { weight: font::Weight::Bold, ..Font::default() }), /// ]) /// .on_link_click(never) /// .size(20) /// .into() /// } /// ``` pub fn rich_text<'a, Link, Message, Theme, Renderer>( spans: impl AsRef<[text::Span<'a, Link, Renderer::Font>]> + 'a, ) -> text::Rich<'a, Link, Message, Theme, Renderer> where Link: Clone + 'static, Theme: text::Catalog + 'a, Renderer: core::text::Renderer, Renderer::Font: 'a, { text::Rich::with_spans(spans) } /// Creates a new [`Span`] of text with the provided content. /// /// A [`Span`] is a fragment of some [`Rich`] text. /// /// [`Span`]: text::Span /// [`Rich`]: text::Rich /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::core::*; } /// # pub type State = (); /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// use iced::font; /// use iced::widget::{rich_text, span}; /// use iced::{color, never, Font}; /// /// #[derive(Debug, Clone)] /// enum Message { /// // ... /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// rich_text![ /// span("I am red!").color(color!(0xff0000)), /// " ", /// span("And I am bold!").font(Font { weight: font::Weight::Bold, ..Font::default() }), /// ] /// .on_link_click(never) /// .size(20) /// .into() /// } /// ``` pub fn span<'a, Link, Font>( text: impl text::IntoFragment<'a>, ) -> text::Span<'a, Link, Font> { text::Span::new(text) } #[cfg(feature = "markdown")] #[doc(inline)] pub use crate::markdown::view as markdown; /// Creates a new [`Checkbox`]. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # /// use iced::widget::checkbox; /// /// struct State { /// is_checked: bool, /// } /// /// enum Message { /// CheckboxToggled(bool), /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// checkbox("Toggle me!", state.is_checked) /// .on_toggle(Message::CheckboxToggled) /// .into() /// } /// /// fn update(state: &mut State, message: Message) { /// match message { /// Message::CheckboxToggled(is_checked) => { /// state.is_checked = is_checked; /// } /// } /// } /// ``` /// ![Checkbox drawn by `iced_wgpu`](https://github.com/iced-rs/iced/blob/7760618fb112074bc40b148944521f312152012a/docs/images/checkbox.png?raw=true) pub fn checkbox<'a, Message, Theme, Renderer>( label: impl Into, is_checked: bool, ) -> Checkbox<'a, Message, Theme, Renderer> where Theme: checkbox::Catalog + 'a, Renderer: core::text::Renderer, { Checkbox::new(label, is_checked) } /// Creates a new [`Radio`]. /// /// Radio buttons let users choose a single option from a bunch of options. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # /// use iced::widget::{column, radio}; /// /// struct State { /// selection: Option, /// } /// /// #[derive(Debug, Clone, Copy)] /// enum Message { /// RadioSelected(Choice), /// } /// /// #[derive(Debug, Clone, Copy, PartialEq, Eq)] /// enum Choice { /// A, /// B, /// C, /// All, /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// let a = radio( /// "A", /// Choice::A, /// state.selection, /// Message::RadioSelected, /// ); /// /// let b = radio( /// "B", /// Choice::B, /// state.selection, /// Message::RadioSelected, /// ); /// /// let c = radio( /// "C", /// Choice::C, /// state.selection, /// Message::RadioSelected, /// ); /// /// let all = radio( /// "All of the above", /// Choice::All, /// state.selection, /// Message::RadioSelected /// ); /// /// column![a, b, c, all].into() /// } /// ``` pub fn radio<'a, Message, Theme, Renderer, V>( label: impl Into, value: V, selected: Option, on_click: impl FnOnce(V) -> Message, ) -> Radio<'a, Message, Theme, Renderer> where Message: Clone, Theme: radio::Catalog + 'a, Renderer: core::text::Renderer, V: Copy + Eq, { Radio::new(label, value, selected, on_click) } /// Creates a new [`Toggler`]. /// /// Togglers let users make binary choices by toggling a switch. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # /// use iced::widget::toggler; /// /// struct State { /// is_checked: bool, /// } /// /// enum Message { /// TogglerToggled(bool), /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// toggler(state.is_checked) /// .label("Toggle me!") /// .on_toggle(Message::TogglerToggled) /// .into() /// } /// /// fn update(state: &mut State, message: Message) { /// match message { /// Message::TogglerToggled(is_checked) => { /// state.is_checked = is_checked; /// } /// } /// } /// ``` pub fn toggler<'a, Message, Theme, Renderer>( is_checked: bool, ) -> Toggler<'a, Message, Theme, Renderer> where Theme: toggler::Catalog + 'a, Renderer: core::text::Renderer, { Toggler::new(is_checked) } /// Creates a new [`TextInput`]. /// /// Text inputs display fields that can be filled with text. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # /// use iced::widget::text_input; /// /// struct State { /// content: String, /// } /// /// #[derive(Debug, Clone)] /// enum Message { /// ContentChanged(String) /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// text_input("Type something here...", &state.content) /// .on_input(Message::ContentChanged) /// .into() /// } /// /// fn update(state: &mut State, message: Message) { /// match message { /// Message::ContentChanged(content) => { /// state.content = content; /// } /// } /// } /// ``` pub fn text_input<'a, Message, Theme, Renderer>( placeholder: &str, value: &str, ) -> TextInput<'a, Message, Theme, Renderer> where Message: Clone, Theme: text_input::Catalog + 'a, Renderer: core::text::Renderer, { TextInput::new(placeholder, value) } /// Creates a new [`TextEditor`]. /// /// Text editors display a multi-line text input for text editing. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # /// use iced::widget::text_editor; /// /// struct State { /// content: text_editor::Content, /// } /// /// #[derive(Debug, Clone)] /// enum Message { /// Edit(text_editor::Action) /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// text_editor(&state.content) /// .placeholder("Type something here...") /// .on_action(Message::Edit) /// .into() /// } /// /// fn update(state: &mut State, message: Message) { /// match message { /// Message::Edit(action) => { /// state.content.perform(action); /// } /// } /// } /// ``` pub fn text_editor<'a, Message, Theme, Renderer>( content: &'a text_editor::Content, ) -> TextEditor<'a, core::text::highlighter::PlainText, Message, Theme, Renderer> where Message: Clone, Theme: text_editor::Catalog + 'a, Renderer: core::text::Renderer, { TextEditor::new(content) } /// Creates a new [`Slider`]. /// /// Sliders let users set a value by moving an indicator. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # /// use iced::widget::slider; /// /// struct State { /// value: f32, /// } /// /// #[derive(Debug, Clone)] /// enum Message { /// ValueChanged(f32), /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// slider(0.0..=100.0, state.value, Message::ValueChanged).into() /// } /// /// fn update(state: &mut State, message: Message) { /// match message { /// Message::ValueChanged(value) => { /// state.value = value; /// } /// } /// } /// ``` pub fn slider<'a, T, Message, Theme>( range: std::ops::RangeInclusive, value: T, on_change: impl Fn(T) -> Message + 'a, ) -> Slider<'a, T, Message, Theme> where T: Copy + From + std::cmp::PartialOrd, Message: Clone, Theme: slider::Catalog + 'a, { Slider::new(range, value, on_change) } /// Creates a new [`VerticalSlider`]. /// /// Sliders let users set a value by moving an indicator. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # /// use iced::widget::vertical_slider; /// /// struct State { /// value: f32, /// } /// /// #[derive(Debug, Clone)] /// enum Message { /// ValueChanged(f32), /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// vertical_slider(0.0..=100.0, state.value, Message::ValueChanged).into() /// } /// /// fn update(state: &mut State, message: Message) { /// match message { /// Message::ValueChanged(value) => { /// state.value = value; /// } /// } /// } /// ``` pub fn vertical_slider<'a, T, Message, Theme>( range: std::ops::RangeInclusive, value: T, on_change: impl Fn(T) -> Message + 'a, ) -> VerticalSlider<'a, T, Message, Theme> where T: Copy + From + std::cmp::PartialOrd, Message: Clone, Theme: vertical_slider::Catalog + 'a, { VerticalSlider::new(range, value, on_change) } /// Creates a new [`PickList`]. /// /// Pick lists display a dropdown list of selectable options. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # /// use iced::widget::pick_list; /// /// struct State { /// favorite: Option, /// } /// /// #[derive(Debug, Clone, Copy, PartialEq, Eq)] /// enum Fruit { /// Apple, /// Orange, /// Strawberry, /// Tomato, /// } /// /// #[derive(Debug, Clone)] /// enum Message { /// FruitSelected(Fruit), /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// let fruits = [ /// Fruit::Apple, /// Fruit::Orange, /// Fruit::Strawberry, /// Fruit::Tomato, /// ]; /// /// pick_list( /// fruits, /// state.favorite, /// Message::FruitSelected, /// ) /// .placeholder("Select your favorite fruit...") /// .into() /// } /// /// fn update(state: &mut State, message: Message) { /// match message { /// Message::FruitSelected(fruit) => { /// state.favorite = Some(fruit); /// } /// } /// } /// /// impl std::fmt::Display for Fruit { /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { /// f.write_str(match self { /// Self::Apple => "Apple", /// Self::Orange => "Orange", /// Self::Strawberry => "Strawberry", /// Self::Tomato => "Tomato", /// }) /// } /// } /// ``` pub fn pick_list<'a, T, L, V, Message, Theme, Renderer>( options: L, selected: Option, on_selected: impl Fn(T) -> Message + 'a, ) -> PickList<'a, T, L, V, Message, Theme, Renderer> where T: ToString + PartialEq + Clone + 'a, L: Borrow<[T]> + 'a, V: Borrow + 'a, Message: Clone, Theme: pick_list::Catalog + overlay::menu::Catalog, Renderer: core::text::Renderer, { PickList::new(options, selected, on_selected) } /// Creates a new [`ComboBox`]. /// /// Combo boxes display a dropdown list of searchable and selectable options. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # /// use iced::widget::combo_box; /// /// struct State { /// fruits: combo_box::State, /// favorite: Option, /// } /// /// #[derive(Debug, Clone)] /// enum Fruit { /// Apple, /// Orange, /// Strawberry, /// Tomato, /// } /// /// #[derive(Debug, Clone)] /// enum Message { /// FruitSelected(Fruit), /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// combo_box( /// &state.fruits, /// "Select your favorite fruit...", /// state.favorite.as_ref(), /// Message::FruitSelected /// ) /// .into() /// } /// /// fn update(state: &mut State, message: Message) { /// match message { /// Message::FruitSelected(fruit) => { /// state.favorite = Some(fruit); /// } /// } /// } /// /// impl std::fmt::Display for Fruit { /// fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { /// f.write_str(match self { /// Self::Apple => "Apple", /// Self::Orange => "Orange", /// Self::Strawberry => "Strawberry", /// Self::Tomato => "Tomato", /// }) /// } /// } /// ``` pub fn combo_box<'a, T, Message, Theme, Renderer>( state: &'a combo_box::State, placeholder: &str, selection: Option<&T>, on_selected: impl Fn(T) -> Message + 'static, ) -> ComboBox<'a, T, Message, Theme, Renderer> where T: std::fmt::Display + Clone, Theme: combo_box::Catalog + 'a, Renderer: core::text::Renderer, { ComboBox::new(state, placeholder, selection, on_selected) } /// Creates a new [`Space`] widget that fills the available /// horizontal space. /// /// This can be useful to separate widgets in a [`Row`]. pub fn horizontal_space() -> Space { Space::with_width(Length::Fill) } /// Creates a new [`Space`] widget that fills the available /// vertical space. /// /// This can be useful to separate widgets in a [`Column`]. pub fn vertical_space() -> Space { Space::with_height(Length::Fill) } /// Creates a horizontal [`Rule`] with the given height. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } } /// # pub type State = (); /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// use iced::widget::horizontal_rule; /// /// #[derive(Clone)] /// enum Message { /// // ..., /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// horizontal_rule(2).into() /// } /// ``` pub fn horizontal_rule<'a, Theme>(height: impl Into) -> Rule<'a, Theme> where Theme: rule::Catalog + 'a, { Rule::horizontal(height) } /// Creates a vertical [`Rule`] with the given width. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } } /// # pub type State = (); /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// use iced::widget::vertical_rule; /// /// #[derive(Clone)] /// enum Message { /// // ..., /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// vertical_rule(2).into() /// } /// ``` pub fn vertical_rule<'a, Theme>(width: impl Into) -> Rule<'a, Theme> where Theme: rule::Catalog + 'a, { Rule::vertical(width) } /// Creates a new [`ProgressBar`]. /// /// Progress bars visualize the progression of an extended computer operation, such as a download, file transfer, or installation. /// /// It expects: /// * an inclusive range of possible values, and /// * the current value of the [`ProgressBar`]. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # /// use iced::widget::progress_bar; /// /// struct State { /// progress: f32, /// } /// /// enum Message { /// // ... /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// progress_bar(0.0..=100.0, state.progress).into() /// } /// ``` pub fn progress_bar<'a, Theme>( range: RangeInclusive, value: f32, ) -> ProgressBar<'a, Theme> where Theme: progress_bar::Catalog + 'a, { ProgressBar::new(range, value) } /// Creates a new [`Image`]. /// /// Images display raster graphics in different formats (PNG, JPG, etc.). /// /// [`Image`]: crate::Image /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } } /// # pub type State = (); /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// use iced::widget::image; /// /// enum Message { /// // ... /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// image("ferris.png").into() /// } /// ``` /// #[cfg(feature = "image")] pub fn image(handle: impl Into) -> crate::Image { crate::Image::new(handle.into()) } /// Creates a new [`Svg`] widget from the given [`Handle`]. /// /// Svg widgets display vector graphics in your application. /// /// [`Svg`]: crate::Svg /// [`Handle`]: crate::svg::Handle /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } } /// # pub type State = (); /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// use iced::widget::svg; /// /// enum Message { /// // ... /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// svg("tiger.svg").into() /// } /// ``` #[cfg(feature = "svg")] pub fn svg<'a, Theme>( handle: impl Into, ) -> crate::Svg<'a, Theme> where Theme: crate::svg::Catalog, { crate::Svg::new(handle) } /// Creates an [`Element`] that displays the iced logo with the given `text_size`. /// /// Useful for showing some love to your favorite GUI library in your "About" screen, /// for instance. #[cfg(feature = "svg")] pub fn iced<'a, Message, Theme, Renderer>( text_size: impl Into, ) -> Element<'a, Message, Theme, Renderer> where Message: 'a, Renderer: core::Renderer + core::text::Renderer + core::svg::Renderer + 'a, Theme: text::Catalog + crate::svg::Catalog + 'a, { use crate::core::{Alignment, Font}; use crate::svg; use std::sync::LazyLock; static LOGO: LazyLock = LazyLock::new(|| { svg::Handle::from_memory(include_bytes!("../assets/iced-logo.svg")) }); let text_size = text_size.into(); row![ svg(LOGO.clone()).width(text_size * 1.3), text("iced").size(text_size).font(Font::MONOSPACE) ] .spacing(text_size.0 / 3.0) .align_y(Alignment::Center) .into() } /// Creates a new [`Canvas`]. /// /// Canvases can be leveraged to draw interactive 2D graphics. /// /// [`Canvas`]: crate::Canvas /// /// # Example: Drawing a Simple Circle /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } /// # pub type State = (); /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # /// use iced::mouse; /// use iced::widget::canvas; /// use iced::{Color, Rectangle, Renderer, Theme}; /// /// // First, we define the data we need for drawing /// #[derive(Debug)] /// struct Circle { /// radius: f32, /// } /// /// // Then, we implement the `Program` trait /// impl canvas::Program for Circle { /// // No internal state /// type State = (); /// /// fn draw( /// &self, /// _state: &(), /// renderer: &Renderer, /// _theme: &Theme, /// bounds: Rectangle, /// _cursor: mouse::Cursor /// ) -> Vec { /// // We prepare a new `Frame` /// let mut frame = canvas::Frame::new(renderer, bounds.size()); /// /// // We create a `Path` representing a simple circle /// let circle = canvas::Path::circle(frame.center(), self.radius); /// /// // And fill it with some color /// frame.fill(&circle, Color::BLACK); /// /// // Then, we produce the geometry /// vec![frame.into_geometry()] /// } /// } /// /// // Finally, we simply use our `Circle` to create the `Canvas`! /// fn view<'a, Message: 'a>(_state: &'a State) -> Element<'a, Message> { /// canvas(Circle { radius: 50.0 }).into() /// } /// ``` #[cfg(feature = "canvas")] pub fn canvas( program: P, ) -> crate::Canvas where Renderer: crate::graphics::geometry::Renderer, P: crate::canvas::Program, { crate::Canvas::new(program) } /// Creates a new [`QRCode`] widget from the given [`Data`]. /// /// QR codes display information in a type of two-dimensional matrix barcode. /// /// [`QRCode`]: crate::QRCode /// [`Data`]: crate::qr_code::Data /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # /// use iced::widget::qr_code; /// /// struct State { /// data: qr_code::Data, /// } /// /// #[derive(Debug, Clone)] /// enum Message { /// // ... /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// qr_code(&state.data).into() /// } /// ``` #[cfg(feature = "qr_code")] pub fn qr_code<'a, Theme>( data: &'a crate::qr_code::Data, ) -> crate::QRCode<'a, Theme> where Theme: crate::qr_code::Catalog + 'a, { crate::QRCode::new(data) } /// Creates a new [`Shader`]. /// /// [`Shader`]: crate::Shader #[cfg(feature = "wgpu")] pub fn shader(program: P) -> crate::Shader where P: crate::shader::Program, { crate::Shader::new(program) } /// Focuses the previous focusable widget. pub fn focus_previous() -> Task { task::effect(Action::widget(operation::focusable::focus_previous())) } /// Focuses the next focusable widget. pub fn focus_next() -> Task { task::effect(Action::widget(operation::focusable::focus_next())) } /// A container intercepting mouse events. pub fn mouse_area<'a, Message, Theme, Renderer>( widget: impl Into>, ) -> MouseArea<'a, Message, Theme, Renderer> where Renderer: core::Renderer, { MouseArea::new(widget) } /// A widget that applies any `Theme` to its contents. pub fn themer<'a, Message, OldTheme, NewTheme, Renderer>( new_theme: NewTheme, content: impl Into>, ) -> Themer< 'a, Message, OldTheme, NewTheme, impl Fn(&OldTheme) -> NewTheme, Renderer, > where Renderer: core::Renderer, NewTheme: Clone, { Themer::new(move |_| new_theme.clone(), content) } /// Creates a [`PaneGrid`] with the given [`pane_grid::State`] and view function. /// /// Pane grids let your users split regions of your application and organize layout dynamically. /// /// # Example /// ```no_run /// # mod iced { pub mod widget { pub use iced_widget::*; } pub use iced_widget::Renderer; pub use iced_widget::core::*; } /// # pub type Element<'a, Message> = iced_widget::core::Element<'a, Message, iced_widget::Theme, iced_widget::Renderer>; /// # /// use iced::widget::{pane_grid, text}; /// /// struct State { /// panes: pane_grid::State, /// } /// /// enum Pane { /// SomePane, /// AnotherKindOfPane, /// } /// /// enum Message { /// PaneDragged(pane_grid::DragEvent), /// PaneResized(pane_grid::ResizeEvent), /// } /// /// fn view(state: &State) -> Element<'_, Message> { /// pane_grid(&state.panes, |pane, state, is_maximized| { /// pane_grid::Content::new(match state { /// Pane::SomePane => text("This is some pane"), /// Pane::AnotherKindOfPane => text("This is another kind of pane"), /// }) /// }) /// .on_drag(Message::PaneDragged) /// .on_resize(10, Message::PaneResized) /// .into() /// } /// ``` pub fn pane_grid<'a, T, Message, Theme, Renderer>( state: &'a pane_grid::State, view: impl Fn( pane_grid::Pane, &'a T, bool, ) -> pane_grid::Content<'a, Message, Theme, Renderer>, ) -> PaneGrid<'a, Message, Theme, Renderer> where Theme: pane_grid::Catalog, Renderer: core::Renderer, { PaneGrid::new(state, view) }