diff options
Diffstat (limited to 'native/src/widget/checkbox.rs')
-rw-r--r-- | native/src/widget/checkbox.rs | 178 |
1 files changed, 98 insertions, 80 deletions
diff --git a/native/src/widget/checkbox.rs b/native/src/widget/checkbox.rs index 8bdb6b78..0d4a43ec 100644 --- a/native/src/widget/checkbox.rs +++ b/native/src/widget/checkbox.rs @@ -1,24 +1,27 @@ //! Show toggle controls using checkboxes. use std::hash::Hash; -use crate::alignment::{self, Alignment}; +use crate::alignment; use crate::event::{self, Event}; use crate::layout; use crate::mouse; -use crate::row; +use crate::renderer; use crate::text; use crate::touch; +use crate::widget::{self, Row, Text}; use crate::{ - Clipboard, Color, Element, Hasher, Layout, Length, Point, Rectangle, Row, - Text, Widget, + Alignment, Clipboard, Color, Element, Hasher, Layout, Length, Point, + Rectangle, Widget, }; +pub use iced_style::checkbox::{Style, StyleSheet}; + /// A box that can be checked. /// /// # Example /// /// ``` -/// # type Checkbox<Message> = iced_native::Checkbox<Message, iced_native::renderer::Null>; +/// # type Checkbox<'a, Message> = iced_native::widget::Checkbox<'a, Message, iced_native::renderer::Null>; /// # /// pub enum Message { /// CheckboxToggled(bool), @@ -31,7 +34,7 @@ use crate::{ /// ///  #[allow(missing_debug_implementations)] -pub struct Checkbox<Message, Renderer: self::Renderer + text::Renderer> { +pub struct Checkbox<'a, Message, Renderer: text::Renderer> { is_checked: bool, on_toggle: Box<dyn Fn(bool) -> Message>, label: String, @@ -41,12 +44,16 @@ pub struct Checkbox<Message, Renderer: self::Renderer + text::Renderer> { text_size: Option<u16>, font: Renderer::Font, text_color: Option<Color>, - style: Renderer::Style, + style_sheet: Box<dyn StyleSheet + 'a>, } -impl<Message, Renderer: self::Renderer + text::Renderer> - Checkbox<Message, Renderer> -{ +impl<'a, Message, Renderer: text::Renderer> Checkbox<'a, Message, Renderer> { + /// The default size of a [`Checkbox`]. + const DEFAULT_SIZE: u16 = 20; + + /// The default spacing of a [`Checkbox`]. + const DEFAULT_SPACING: u16 = 15; + /// Creates a new [`Checkbox`]. /// /// It expects: @@ -64,12 +71,12 @@ impl<Message, Renderer: self::Renderer + text::Renderer> on_toggle: Box::new(f), label: label.into(), width: Length::Shrink, - size: <Renderer as self::Renderer>::DEFAULT_SIZE, - spacing: Renderer::DEFAULT_SPACING, + size: Self::DEFAULT_SIZE, + spacing: Self::DEFAULT_SPACING, text_size: None, font: Renderer::Font::default(), text_color: None, - style: Renderer::Style::default(), + style_sheet: Default::default(), } } @@ -112,16 +119,19 @@ impl<Message, Renderer: self::Renderer + text::Renderer> } /// Sets the style of the [`Checkbox`]. - pub fn style(mut self, style: impl Into<Renderer::Style>) -> Self { - self.style = style.into(); + pub fn style( + mut self, + style_sheet: impl Into<Box<dyn StyleSheet + 'a>>, + ) -> Self { + self.style_sheet = style_sheet.into(); self } } -impl<Message, Renderer> Widget<Message, Renderer> - for Checkbox<Message, Renderer> +impl<'a, Message, Renderer> Widget<Message, Renderer> + for Checkbox<'a, Message, Renderer> where - Renderer: self::Renderer + text::Renderer + row::Renderer, + Renderer: text::Renderer, { fn width(&self) -> Length { self.width @@ -180,43 +190,84 @@ where event::Status::Ignored } + fn mouse_interaction( + &self, + layout: Layout<'_>, + cursor_position: Point, + _viewport: &Rectangle, + ) -> mouse::Interaction { + if layout.bounds().contains(cursor_position) { + mouse::Interaction::Pointer + } else { + mouse::Interaction::default() + } + } + fn draw( &self, renderer: &mut Renderer, - defaults: &Renderer::Defaults, + style: &renderer::Style, layout: Layout<'_>, cursor_position: Point, _viewport: &Rectangle, - ) -> Renderer::Output { + ) { let bounds = layout.bounds(); + let is_mouse_over = bounds.contains(cursor_position); + let mut children = layout.children(); - let checkbox_layout = children.next().unwrap(); - let label_layout = children.next().unwrap(); - let checkbox_bounds = checkbox_layout.bounds(); - - let label = text::Renderer::draw( - renderer, - defaults, - label_layout.bounds(), - &self.label, - self.text_size.unwrap_or(renderer.default_size()), - self.font, - self.text_color, - alignment::Horizontal::Left, - alignment::Vertical::Center, - ); + { + let layout = children.next().unwrap(); + let bounds = layout.bounds(); - let is_mouse_over = bounds.contains(cursor_position); + let style = if is_mouse_over { + self.style_sheet.hovered(self.is_checked) + } else { + self.style_sheet.active(self.is_checked) + }; + + renderer.fill_quad( + renderer::Quad { + bounds, + border_radius: style.border_radius, + border_width: style.border_width, + border_color: style.border_color, + }, + style.background, + ); - self::Renderer::draw( - renderer, - checkbox_bounds, - self.is_checked, - is_mouse_over, - label, - &self.style, - ) + if self.is_checked { + renderer.fill_text(text::Text { + content: &Renderer::CHECKMARK_ICON.to_string(), + font: Renderer::ICON_FONT, + size: bounds.height * 0.7, + bounds: Rectangle { + x: bounds.center_x(), + y: bounds.center_y(), + ..bounds + }, + color: style.checkmark_color, + horizontal_alignment: alignment::Horizontal::Center, + vertical_alignment: alignment::Vertical::Center, + }); + } + } + + { + let label_layout = children.next().unwrap(); + + widget::text::draw( + renderer, + style, + label_layout, + &self.label, + self.font, + self.text_size, + self.text_color, + alignment::Horizontal::Left, + alignment::Vertical::Center, + ); + } } fn hash_layout(&self, state: &mut Hasher) { @@ -227,47 +278,14 @@ where } } -/// The renderer of a [`Checkbox`]. -/// -/// Your [renderer] will need to implement this trait before being -/// able to use a [`Checkbox`] in your user interface. -/// -/// [renderer]: crate::Renderer -pub trait Renderer: crate::Renderer { - /// The style supported by this renderer. - type Style: Default; - - /// The default size of a [`Checkbox`]. - const DEFAULT_SIZE: u16; - - /// The default spacing of a [`Checkbox`]. - const DEFAULT_SPACING: u16; - - /// Draws a [`Checkbox`]. - /// - /// It receives: - /// * the bounds of the [`Checkbox`] - /// * whether the [`Checkbox`] is selected or not - /// * whether the mouse is over the [`Checkbox`] or not - /// * the drawn label of the [`Checkbox`] - fn draw( - &mut self, - bounds: Rectangle, - is_checked: bool, - is_mouse_over: bool, - label: Self::Output, - style: &Self::Style, - ) -> Self::Output; -} - -impl<'a, Message, Renderer> From<Checkbox<Message, Renderer>> +impl<'a, Message, Renderer> From<Checkbox<'a, Message, Renderer>> for Element<'a, Message, Renderer> where - Renderer: 'a + self::Renderer + text::Renderer + row::Renderer, + Renderer: 'a + text::Renderer, Message: 'a, { fn from( - checkbox: Checkbox<Message, Renderer>, + checkbox: Checkbox<'a, Message, Renderer>, ) -> Element<'a, Message, Renderer> { Element::new(checkbox) } |