//! Allow your users to perform actions by pressing a button. use crate::overlay; use crate::widget::tree::{self, Tree}; use crate::{Element, Widget}; use iced_native::event::{self, Event}; use iced_native::layout; use iced_native::mouse; use iced_native::renderer; use iced_native::widget::button; use iced_native::{ Clipboard, Layout, Length, Padding, Point, Rectangle, Shell, }; pub use iced_style::button::{Style, StyleSheet}; use button::State; /// A generic widget that produces a message when pressed. /// /// ``` /// # type Button<'a, Message> = /// # iced_pure::widget::Button<'a, Message, iced_native::renderer::Null>; /// # /// #[derive(Clone)] /// enum Message { /// ButtonPressed, /// } /// /// let button = Button::new("Press me!").on_press(Message::ButtonPressed); /// ``` /// /// If a [`Button::on_press`] handler is not set, the resulting [`Button`] will /// be disabled: /// /// ``` /// # type Button<'a, Message> = /// # iced_pure::widget::Button<'a, Message, iced_native::renderer::Null>; /// # /// #[derive(Clone)] /// enum Message { /// ButtonPressed, /// } /// /// fn disabled_button<'a>() -> Button<'a, Message> { /// Button::new("I'm disabled!") /// } /// /// fn enabled_button<'a>() -> Button<'a, Message> { /// disabled_button().on_press(Message::ButtonPressed) /// } /// ``` pub struct Button<'a, Message, Renderer> { content: Element<'a, Message, Renderer>, on_press: Option, style_sheet: Box, width: Length, height: Length, padding: Padding, } impl<'a, Message, Renderer> Button<'a, Message, Renderer> { /// Creates a new [`Button`] with the given content. pub fn new(content: impl Into>) -> Self { Button { content: content.into(), on_press: None, style_sheet: Default::default(), width: Length::Shrink, height: Length::Shrink, padding: Padding::new(5), } } /// Sets the width of the [`Button`]. pub fn width(mut self, width: Length) -> Self { self.width = width; self } /// Sets the height of the [`Button`]. pub fn height(mut self, height: Length) -> Self { self.height = height; self } /// Sets the [`Padding`] of the [`Button`]. pub fn padding>(mut self, padding: P) -> Self { self.padding = padding.into(); self } /// Sets the message that will be produced when the [`Button`] is pressed. /// /// Unless `on_press` is called, the [`Button`] will be disabled. pub fn on_press(mut self, msg: Message) -> Self { self.on_press = Some(msg); self } /// Sets the style of the [`Button`]. pub fn style( mut self, style_sheet: impl Into>, ) -> Self { self.style_sheet = style_sheet.into(); self } } impl<'a, Message, Renderer> Widget for Button<'a, Message, Renderer> where Message: 'a + Clone, Renderer: 'a + iced_native::Renderer, { fn tag(&self) -> tree::Tag { tree::Tag::of::() } fn state(&self) -> tree::State { tree::State::new(State::new()) } fn children(&self) -> Vec { vec![Tree::new(&self.content)] } fn diff(&self, tree: &mut Tree) { tree.diff_children(std::slice::from_ref(&self.content)) } fn width(&self) -> Length { self.width } fn height(&self) -> Length { self.height } fn layout( &self, renderer: &Renderer, limits: &layout::Limits, ) -> layout::Node { button::layout( renderer, limits, self.width, self.height, self.padding, |renderer, limits| { self.content.as_widget().layout(renderer, &limits) }, ) } fn on_event( &mut self, tree: &mut Tree, event: Event, layout: Layout<'_>, cursor_position: Point, renderer: &Renderer, clipboard: &mut dyn Clipboard, shell: &mut Shell<'_, Message>, ) -> event::Status { if let event::Status::Captured = self.content.as_widget_mut().on_event( &mut tree.children[0], event.clone(), layout.children().next().unwrap(), cursor_position, renderer, clipboard, shell, ) { return event::Status::Captured; } button::update( event, layout, cursor_position, shell, &self.on_press, || tree.state.downcast_mut::(), ) } fn draw( &self, tree: &Tree, renderer: &mut Renderer, _style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, _viewport: &Rectangle, ) { let bounds = layout.bounds(); let content_layout = layout.children().next().unwrap(); let styling = button::draw( renderer, bounds, cursor_position, self.on_press.is_some(), self.style_sheet.as_ref(), || tree.state.downcast_ref::(), ); self.content.as_widget().draw( &tree.children[0], renderer, &renderer::Style { text_color: styling.text_color, }, content_layout, cursor_position, &bounds, ); } fn mouse_interaction( &self, _tree: &Tree, layout: Layout<'_>, cursor_position: Point, _viewport: &Rectangle, _renderer: &Renderer, ) -> mouse::Interaction { button::mouse_interaction( layout, cursor_position, self.on_press.is_some(), ) } fn overlay<'b>( &'b self, tree: &'b mut Tree, layout: Layout<'_>, renderer: &Renderer, ) -> Option> { self.content.as_widget().overlay( &mut tree.children[0], layout.children().next().unwrap(), renderer, ) } } impl<'a, Message, Renderer> Into> for Button<'a, Message, Renderer> where Message: Clone + 'a, Renderer: iced_native::Renderer + 'a, { fn into(self) -> Element<'a, Message, Renderer> { Element::new(self) } }