From 3a0d34c0240f4421737a6a08761f99d6f8140d02 Mon Sep 17 00:00:00 2001 From: Héctor Ramón Jiménez Date: Sat, 4 Mar 2023 05:37:11 +0100 Subject: Create `iced_widget` subcrate and re-organize the whole codebase --- native/src/widget/button.rs | 455 -------------------------------------------- 1 file changed, 455 deletions(-) delete mode 100644 native/src/widget/button.rs (limited to 'native/src/widget/button.rs') diff --git a/native/src/widget/button.rs b/native/src/widget/button.rs deleted file mode 100644 index 39387173..00000000 --- a/native/src/widget/button.rs +++ /dev/null @@ -1,455 +0,0 @@ -//! Allow your users to perform actions by pressing a button. -//! -//! A [`Button`] has some local [`State`]. -use crate::event::{self, Event}; -use crate::layout; -use crate::mouse; -use crate::overlay; -use crate::renderer; -use crate::touch; -use crate::widget::tree::{self, Tree}; -use crate::widget::Operation; -use crate::{ - Background, Clipboard, Color, Element, Layout, Length, Padding, Point, - Rectangle, Shell, Vector, Widget, -}; - -pub use iced_style::button::{Appearance, StyleSheet}; - -/// A generic widget that produces a message when pressed. -/// -/// ``` -/// # type Button<'a, Message> = -/// # iced_native::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_native::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) -/// } -/// ``` -#[allow(missing_debug_implementations)] -pub struct Button<'a, Message, Renderer> -where - Renderer: crate::Renderer, - Renderer::Theme: StyleSheet, -{ - content: Element<'a, Message, Renderer>, - on_press: Option, - width: Length, - height: Length, - padding: Padding, - style: ::Style, -} - -impl<'a, Message, Renderer> Button<'a, Message, Renderer> -where - Renderer: crate::Renderer, - Renderer::Theme: StyleSheet, -{ - /// Creates a new [`Button`] with the given content. - pub fn new(content: impl Into>) -> Self { - Button { - content: content.into(), - on_press: None, - width: Length::Shrink, - height: Length::Shrink, - padding: Padding::new(5.0), - style: ::Style::default(), - } - } - - /// Sets the width of the [`Button`]. - pub fn width(mut self, width: impl Into) -> Self { - self.width = width.into(); - self - } - - /// Sets the height of the [`Button`]. - pub fn height(mut self, height: impl Into) -> Self { - self.height = height.into(); - 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 variant of this [`Button`]. - pub fn style( - mut self, - style: ::Style, - ) -> Self { - self.style = style; - self - } -} - -impl<'a, Message, Renderer> Widget - for Button<'a, Message, Renderer> -where - Message: 'a + Clone, - Renderer: 'a + crate::Renderer, - Renderer::Theme: StyleSheet, -{ - 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 { - layout( - renderer, - limits, - self.width, - self.height, - self.padding, - |renderer, limits| { - self.content.as_widget().layout(renderer, limits) - }, - ) - } - - fn operate( - &self, - tree: &mut Tree, - layout: Layout<'_>, - renderer: &Renderer, - operation: &mut dyn Operation, - ) { - operation.container(None, &mut |operation| { - self.content.as_widget().operate( - &mut tree.children[0], - layout.children().next().unwrap(), - renderer, - operation, - ); - }); - } - - 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; - } - - update( - event, - layout, - cursor_position, - shell, - &self.on_press, - || tree.state.downcast_mut::(), - ) - } - - fn draw( - &self, - tree: &Tree, - renderer: &mut Renderer, - theme: &Renderer::Theme, - _style: &renderer::Style, - layout: Layout<'_>, - cursor_position: Point, - _viewport: &Rectangle, - ) { - let bounds = layout.bounds(); - let content_layout = layout.children().next().unwrap(); - - let styling = draw( - renderer, - bounds, - cursor_position, - self.on_press.is_some(), - theme, - &self.style, - || tree.state.downcast_ref::(), - ); - - self.content.as_widget().draw( - &tree.children[0], - renderer, - theme, - &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 { - mouse_interaction(layout, cursor_position, self.on_press.is_some()) - } - - fn overlay<'b>( - &'b mut self, - tree: &'b mut Tree, - layout: Layout<'_>, - renderer: &Renderer, - ) -> Option> { - self.content.as_widget_mut().overlay( - &mut tree.children[0], - layout.children().next().unwrap(), - renderer, - ) - } -} - -impl<'a, Message, Renderer> From> - for Element<'a, Message, Renderer> -where - Message: Clone + 'a, - Renderer: crate::Renderer + 'a, - Renderer::Theme: StyleSheet, -{ - fn from(button: Button<'a, Message, Renderer>) -> Self { - Self::new(button) - } -} - -/// The local state of a [`Button`]. -#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] -pub struct State { - is_pressed: bool, -} - -impl State { - /// Creates a new [`State`]. - pub fn new() -> State { - State::default() - } -} - -/// Processes the given [`Event`] and updates the [`State`] of a [`Button`] -/// accordingly. -pub fn update<'a, Message: Clone>( - event: Event, - layout: Layout<'_>, - cursor_position: Point, - shell: &mut Shell<'_, Message>, - on_press: &Option, - state: impl FnOnce() -> &'a mut State, -) -> event::Status { - match event { - Event::Mouse(mouse::Event::ButtonPressed(mouse::Button::Left)) - | Event::Touch(touch::Event::FingerPressed { .. }) => { - if on_press.is_some() { - let bounds = layout.bounds(); - - if bounds.contains(cursor_position) { - let state = state(); - - state.is_pressed = true; - - return event::Status::Captured; - } - } - } - Event::Mouse(mouse::Event::ButtonReleased(mouse::Button::Left)) - | Event::Touch(touch::Event::FingerLifted { .. }) => { - if let Some(on_press) = on_press.clone() { - let state = state(); - - if state.is_pressed { - state.is_pressed = false; - - let bounds = layout.bounds(); - - if bounds.contains(cursor_position) { - shell.publish(on_press); - } - - return event::Status::Captured; - } - } - } - Event::Touch(touch::Event::FingerLost { .. }) => { - let state = state(); - - state.is_pressed = false; - } - _ => {} - } - - event::Status::Ignored -} - -/// Draws a [`Button`]. -pub fn draw<'a, Renderer: crate::Renderer>( - renderer: &mut Renderer, - bounds: Rectangle, - cursor_position: Point, - is_enabled: bool, - style_sheet: &dyn StyleSheet< - Style = ::Style, - >, - style: &::Style, - state: impl FnOnce() -> &'a State, -) -> Appearance -where - Renderer::Theme: StyleSheet, -{ - let is_mouse_over = bounds.contains(cursor_position); - - let styling = if !is_enabled { - style_sheet.disabled(style) - } else if is_mouse_over { - let state = state(); - - if state.is_pressed { - style_sheet.pressed(style) - } else { - style_sheet.hovered(style) - } - } else { - style_sheet.active(style) - }; - - if styling.background.is_some() || styling.border_width > 0.0 { - if styling.shadow_offset != Vector::default() { - // TODO: Implement proper shadow support - renderer.fill_quad( - renderer::Quad { - bounds: Rectangle { - x: bounds.x + styling.shadow_offset.x, - y: bounds.y + styling.shadow_offset.y, - ..bounds - }, - border_radius: styling.border_radius.into(), - border_width: 0.0, - border_color: Color::TRANSPARENT, - }, - Background::Color([0.0, 0.0, 0.0, 0.5].into()), - ); - } - - renderer.fill_quad( - renderer::Quad { - bounds, - border_radius: styling.border_radius.into(), - border_width: styling.border_width, - border_color: styling.border_color, - }, - styling - .background - .unwrap_or(Background::Color(Color::TRANSPARENT)), - ); - } - - styling -} - -/// Computes the layout of a [`Button`]. -pub fn layout( - renderer: &Renderer, - limits: &layout::Limits, - width: Length, - height: Length, - padding: Padding, - layout_content: impl FnOnce(&Renderer, &layout::Limits) -> layout::Node, -) -> layout::Node { - let limits = limits.width(width).height(height); - - let mut content = layout_content(renderer, &limits.pad(padding)); - let padding = padding.fit(content.size(), limits.max()); - let size = limits.pad(padding).resolve(content.size()).pad(padding); - - content.move_to(Point::new(padding.left, padding.top)); - - layout::Node::with_children(size, vec![content]) -} - -/// Returns the [`mouse::Interaction`] of a [`Button`]. -pub fn mouse_interaction( - layout: Layout<'_>, - cursor_position: Point, - is_enabled: bool, -) -> mouse::Interaction { - let is_mouse_over = layout.bounds().contains(cursor_position); - - if is_mouse_over && is_enabled { - mouse::Interaction::Pointer - } else { - mouse::Interaction::default() - } -} -- cgit