diff options
Diffstat (limited to 'web')
| -rw-r--r-- | web/src/lib.rs | 5 | ||||
| -rw-r--r-- | web/src/widget/button.rs | 100 | ||||
| -rw-r--r-- | web/src/widget/checkbox.rs | 58 | ||||
| -rw-r--r-- | web/src/widget/column.rs | 106 | ||||
| -rw-r--r-- | web/src/widget/image.rs | 50 | ||||
| -rw-r--r-- | web/src/widget/radio.rs | 67 | ||||
| -rw-r--r-- | web/src/widget/row.rs | 108 | ||||
| -rw-r--r-- | web/src/widget/slider.rs | 59 | ||||
| -rw-r--r-- | web/src/widget/text.rs | 108 | 
9 files changed, 643 insertions, 18 deletions
| diff --git a/web/src/lib.rs b/web/src/lib.rs index 6252f2be..00a85cf5 100644 --- a/web/src/lib.rs +++ b/web/src/lib.rs @@ -7,7 +7,10 @@ pub mod widget;  pub use bus::Bus;  pub use element::Element; -pub use iced_core::{Align, Background, Color, Length}; +pub use iced_core::{ +    Align, Background, Color, Font, HorizontalAlignment, Length, +    VerticalAlignment, +};  pub use widget::*;  pub trait Application { diff --git a/web/src/widget/button.rs b/web/src/widget/button.rs index 257034a7..ddf67743 100644 --- a/web/src/widget/button.rs +++ b/web/src/widget/button.rs @@ -1,11 +1,103 @@ -use crate::{Bus, Element, Widget}; +use crate::{Background, Bus, Element, Length, Widget};  use dodrio::bumpalo; -pub use iced_core::button::State; +/// A generic widget that produces a message when clicked. +pub struct Button<'a, Message> { +    content: Element<'a, Message>, +    on_press: Option<Message>, +    width: Length, +    min_width: u32, +    padding: u16, +    background: Option<Background>, +    border_radius: u16, +} + +impl<'a, Message> Button<'a, Message> { +    /// Creates a new [`Button`] with some local [`State`] and the given +    /// content. +    /// +    /// [`Button`]: struct.Button.html +    /// [`State`]: struct.State.html +    pub fn new<E>(_state: &'a mut State, content: E) -> Self +    where +        E: Into<Element<'a, Message>>, +    { +        Button { +            content: content.into(), +            on_press: None, +            width: Length::Shrink, +            min_width: 0, +            padding: 0, +            background: None, +            border_radius: 0, +        } +    } + +    /// Sets the width of the [`Button`]. +    /// +    /// [`Button`]: struct.Button.html +    pub fn width(mut self, width: Length) -> Self { +        self.width = width; +        self +    } + +    /// Sets the minimum width of the [`Button`]. +    /// +    /// [`Button`]: struct.Button.html +    pub fn min_width(mut self, min_width: u32) -> Self { +        self.min_width = min_width; +        self +    } + +    /// Sets the padding of the [`Button`]. +    /// +    /// [`Button`]: struct.Button.html +    pub fn padding(mut self, padding: u16) -> Self { +        self.padding = padding; +        self +    } -pub type Button<'a, Message> = -    iced_core::Button<'a, Message, Element<'a, Message>>; +    /// Sets the [`Background`] of the [`Button`]. +    /// +    /// [`Button`]: struct.Button.html +    /// [`Background`]: ../../struct.Background.html +    pub fn background(mut self, background: Background) -> Self { +        self.background = Some(background); +        self +    } + +    /// Sets the border radius of the [`Button`]. +    /// +    /// [`Button`]: struct.Button.html +    pub fn border_radius(mut self, border_radius: u16) -> Self { +        self.border_radius = border_radius; +        self +    } + +    /// Sets the message that will be produced when the [`Button`] is pressed. +    /// +    /// [`Button`]: struct.Button.html +    pub fn on_press(mut self, msg: Message) -> Self { +        self.on_press = Some(msg); +        self +    } +} + +/// The local state of a [`Button`]. +/// +/// [`Button`]: struct.Button.html +#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] +pub struct State; + +impl State { +    /// Creates a new [`State`]. +    /// +    /// [`State`]: struct.State.html +    pub fn new() -> State { +        State::default() +    } +}  impl<'a, Message> Widget<Message> for Button<'a, Message>  where diff --git a/web/src/widget/checkbox.rs b/web/src/widget/checkbox.rs index 72f0a2aa..8bcef816 100644 --- a/web/src/widget/checkbox.rs +++ b/web/src/widget/checkbox.rs @@ -1,8 +1,62 @@ -use crate::{Bus, Element, Widget}; +use crate::{Bus, Color, Element, Widget};  use dodrio::bumpalo; -pub use iced_core::Checkbox; +/// A box that can be checked. +/// +/// # Example +/// +/// ``` +/// # use iced_web::Checkbox; +/// +/// pub enum Message { +///     CheckboxToggled(bool), +/// } +/// +/// let is_checked = true; +/// +/// Checkbox::new(is_checked, "Toggle me!", Message::CheckboxToggled); +/// ``` +/// +///  +pub struct Checkbox<Message> { +    is_checked: bool, +    on_toggle: Box<dyn Fn(bool) -> Message>, +    label: String, +    label_color: Option<Color>, +} + +impl<Message> Checkbox<Message> { +    /// Creates a new [`Checkbox`]. +    /// +    /// It expects: +    ///   * a boolean describing whether the [`Checkbox`] is checked or not +    ///   * the label of the [`Checkbox`] +    ///   * a function that will be called when the [`Checkbox`] is toggled. It +    ///     will receive the new state of the [`Checkbox`] and must produce a +    ///     `Message`. +    /// +    /// [`Checkbox`]: struct.Checkbox.html +    pub fn new<F>(is_checked: bool, label: &str, f: F) -> Self +    where +        F: 'static + Fn(bool) -> Message, +    { +        Checkbox { +            is_checked, +            on_toggle: Box::new(f), +            label: String::from(label), +            label_color: None, +        } +    } + +    /// Sets the color of the label of the [`Checkbox`]. +    /// +    /// [`Checkbox`]: struct.Checkbox.html +    pub fn label_color<C: Into<Color>>(mut self, color: C) -> Self { +        self.label_color = Some(color.into()); +        self +    } +}  impl<Message> Widget<Message> for Checkbox<Message>  where diff --git a/web/src/widget/column.rs b/web/src/widget/column.rs index becd6bc6..cea50f6d 100644 --- a/web/src/widget/column.rs +++ b/web/src/widget/column.rs @@ -1,8 +1,110 @@ -use crate::{Bus, Element, Widget}; +use crate::{Align, Bus, Element, Length, Widget};  use dodrio::bumpalo; +use std::u32; -pub type Column<'a, Message> = iced_core::Column<Element<'a, Message>>; +/// A container that distributes its contents vertically. +/// +/// A [`Column`] will try to fill the horizontal space of its container. +/// +/// [`Column`]: struct.Column.html +pub struct Column<'a, Message> { +    spacing: u16, +    padding: u16, +    width: Length, +    height: Length, +    max_width: u32, +    max_height: u32, +    align_items: Align, +    children: Vec<Element<'a, Message>>, +} + +impl<'a, Message> Column<'a, Message> { +    /// Creates an empty [`Column`]. +    /// +    /// [`Column`]: struct.Column.html +    pub fn new() -> Self { +        Column { +            spacing: 0, +            padding: 0, +            width: Length::Fill, +            height: Length::Shrink, +            max_width: u32::MAX, +            max_height: u32::MAX, +            align_items: Align::Start, +            children: Vec::new(), +        } +    } + +    /// Sets the vertical spacing _between_ elements. +    /// +    /// Custom margins per element do not exist in Iced. You should use this +    /// method instead! While less flexible, it helps you keep spacing between +    /// elements consistent. +    pub fn spacing(mut self, units: u16) -> Self { +        self.spacing = units; +        self +    } + +    /// Sets the padding of the [`Column`]. +    /// +    /// [`Column`]: struct.Column.html +    pub fn padding(mut self, units: u16) -> Self { +        self.padding = units; +        self +    } + +    /// Sets the width of the [`Column`]. +    /// +    /// [`Column`]: struct.Column.html +    pub fn width(mut self, width: Length) -> Self { +        self.width = width; +        self +    } + +    /// Sets the height of the [`Column`]. +    /// +    /// [`Column`]: struct.Column.html +    pub fn height(mut self, height: Length) -> Self { +        self.height = height; +        self +    } + +    /// Sets the maximum width of the [`Column`]. +    /// +    /// [`Column`]: struct.Column.html +    pub fn max_width(mut self, max_width: u32) -> Self { +        self.max_width = max_width; +        self +    } + +    /// Sets the maximum height of the [`Column`] in pixels. +    /// +    /// [`Column`]: struct.Column.html +    pub fn max_height(mut self, max_height: u32) -> Self { +        self.max_height = max_height; +        self +    } + +    /// Sets the horizontal alignment of the contents of the [`Column`] . +    /// +    /// [`Column`]: struct.Column.html +    pub fn align_items(mut self, align: Align) -> Self { +        self.align_items = align; +        self +    } + +    /// Adds an element to the [`Column`]. +    /// +    /// [`Column`]: struct.Column.html +    pub fn push<E>(mut self, child: E) -> Self +    where +        E: Into<Element<'a, Message>>, +    { +        self.children.push(child.into()); +        self +    } +}  impl<'a, Message> Widget<Message> for Column<'a, Message> {      fn node<'b>( diff --git a/web/src/widget/image.rs b/web/src/widget/image.rs index bd3e5daf..ab510bdb 100644 --- a/web/src/widget/image.rs +++ b/web/src/widget/image.rs @@ -2,7 +2,55 @@ use crate::{Bus, Element, Length, Widget};  use dodrio::bumpalo; -pub use iced_core::Image; +/// A frame that displays an image while keeping aspect ratio. +/// +/// # Example +/// +/// ``` +/// # use iced_web::Image; +/// +/// let image = Image::new("resources/ferris.png"); +/// ``` +#[derive(Debug)] +pub struct Image { +    /// The image path +    pub path: String, + +    /// The width of the image +    pub width: Length, + +    /// The height of the image +    pub height: Length, +} + +impl Image { +    /// Creates a new [`Image`] with the given path. +    /// +    /// [`Image`]: struct.Image.html +    pub fn new<T: Into<String>>(path: T) -> Self { +        Image { +            path: path.into(), +            width: Length::Shrink, +            height: Length::Shrink, +        } +    } + +    /// Sets the width of the [`Image`] boundaries. +    /// +    /// [`Image`]: struct.Image.html +    pub fn width(mut self, width: Length) -> Self { +        self.width = width; +        self +    } + +    /// Sets the height of the [`Image`] boundaries. +    /// +    /// [`Image`]: struct.Image.html +    pub fn height(mut self, height: Length) -> Self { +        self.height = height; +        self +    } +}  impl<Message> Widget<Message> for Image {      fn node<'b>( diff --git a/web/src/widget/radio.rs b/web/src/widget/radio.rs index d249ad26..a0b8fc43 100644 --- a/web/src/widget/radio.rs +++ b/web/src/widget/radio.rs @@ -1,8 +1,71 @@ -use crate::{Bus, Element, Widget}; +use crate::{Bus, Color, Element, Widget};  use dodrio::bumpalo; -pub use iced_core::Radio; +/// A circular button representing a choice. +/// +/// # Example +/// ``` +/// # use iced_web::Radio; +/// +/// #[derive(Debug, Clone, Copy, PartialEq, Eq)] +/// pub enum Choice { +///     A, +///     B, +/// } +/// +/// #[derive(Debug, Clone, Copy)] +/// pub enum Message { +///     RadioSelected(Choice), +/// } +/// +/// let selected_choice = Some(Choice::A); +/// +/// Radio::new(Choice::A, "This is A", selected_choice, Message::RadioSelected); +/// +/// Radio::new(Choice::B, "This is B", selected_choice, Message::RadioSelected); +/// ``` +/// +///  +pub struct Radio<Message> { +    is_selected: bool, +    on_click: Message, +    label: String, +    label_color: Option<Color>, +} + +impl<Message> Radio<Message> { +    /// Creates a new [`Radio`] button. +    /// +    /// It expects: +    ///   * the value related to the [`Radio`] button +    ///   * the label of the [`Radio`] button +    ///   * the current selected value +    ///   * a function that will be called when the [`Radio`] is selected. It +    ///   receives the value of the radio and must produce a `Message`. +    /// +    /// [`Radio`]: struct.Radio.html +    pub fn new<F, V>(value: V, label: &str, selected: Option<V>, f: F) -> Self +    where +        V: Eq + Copy, +        F: 'static + Fn(V) -> Message, +    { +        Radio { +            is_selected: Some(value) == selected, +            on_click: f(value), +            label: String::from(label), +            label_color: None, +        } +    } + +    /// Sets the `Color` of the label of the [`Radio`]. +    /// +    /// [`Radio`]: struct.Radio.html +    pub fn label_color<C: Into<Color>>(mut self, color: C) -> Self { +        self.label_color = Some(color.into()); +        self +    } +}  impl<Message> Widget<Message> for Radio<Message>  where diff --git a/web/src/widget/row.rs b/web/src/widget/row.rs index cf6ae594..44cacd50 100644 --- a/web/src/widget/row.rs +++ b/web/src/widget/row.rs @@ -1,8 +1,112 @@ -use crate::{Bus, Element, Widget}; +use crate::{Align, Bus, Element, Length, Widget};  use dodrio::bumpalo; +use std::u32; -pub type Row<'a, Message> = iced_core::Row<Element<'a, Message>>; +/// A container that distributes its contents horizontally. +/// +/// A [`Row`] will try to fill the horizontal space of its container. +/// +/// [`Row`]: struct.Row.html +#[allow(missing_docs)] +pub struct Row<'a, Message> { +    spacing: u16, +    padding: u16, +    width: Length, +    height: Length, +    max_width: u32, +    max_height: u32, +    align_items: Align, +    children: Vec<Element<'a, Message>>, +} + +impl<'a, Message> Row<'a, Message> { +    /// Creates an empty [`Row`]. +    /// +    /// [`Row`]: struct.Row.html +    pub fn new() -> Self { +        Row { +            spacing: 0, +            padding: 0, +            width: Length::Fill, +            height: Length::Shrink, +            max_width: u32::MAX, +            max_height: u32::MAX, +            align_items: Align::Start, +            children: Vec::new(), +        } +    } + +    /// Sets the horizontal spacing _between_ elements. +    /// +    /// Custom margins per element do not exist in Iced. You should use this +    /// method instead! While less flexible, it helps you keep spacing between +    /// elements consistent. +    pub fn spacing(mut self, units: u16) -> Self { +        self.spacing = units; +        self +    } + +    /// Sets the padding of the [`Row`]. +    /// +    /// [`Row`]: struct.Row.html +    pub fn padding(mut self, units: u16) -> Self { +        self.padding = units; +        self +    } + +    /// Sets the width of the [`Row`]. +    /// +    /// [`Row`]: struct.Row.html +    pub fn width(mut self, width: Length) -> Self { +        self.width = width; +        self +    } + +    /// Sets the height of the [`Row`]. +    /// +    /// [`Row`]: struct.Row.html +    pub fn height(mut self, height: Length) -> Self { +        self.height = height; +        self +    } + +    /// Sets the maximum width of the [`Row`]. +    /// +    /// [`Row`]: struct.Row.html +    pub fn max_width(mut self, max_width: u32) -> Self { +        self.max_width = max_width; +        self +    } + +    /// Sets the maximum height of the [`Row`]. +    /// +    /// [`Row`]: struct.Row.html +    pub fn max_height(mut self, max_height: u32) -> Self { +        self.max_height = max_height; +        self +    } + +    /// Sets the vertical alignment of the contents of the [`Row`] . +    /// +    /// [`Row`]: struct.Row.html +    pub fn align_items(mut self, align: Align) -> Self { +        self.align_items = align; +        self +    } + +    /// Adds an [`Element`] to the [`Row`]. +    /// +    /// [`Element`]: ../struct.Element.html +    /// [`Row`]: struct.Row.html +    pub fn push<E>(mut self, child: E) -> Self +    where +        E: Into<Element<'a, Message>>, +    { +        self.children.push(child.into()); +        self +    } +}  impl<'a, Message> Widget<Message> for Row<'a, Message> {      fn node<'b>( diff --git a/web/src/widget/slider.rs b/web/src/widget/slider.rs index 54b2fdf6..acdef0a1 100644 --- a/web/src/widget/slider.rs +++ b/web/src/widget/slider.rs @@ -1,8 +1,55 @@ -use crate::{Bus, Element, Widget}; +use crate::{Bus, Element, Length, Widget};  use dodrio::bumpalo; +use std::{ops::RangeInclusive, rc::Rc}; -pub use iced_core::slider::*; +pub struct Slider<'a, Message> { +    _state: &'a mut State, +    range: RangeInclusive<f32>, +    value: f32, +    on_change: Rc<Box<dyn Fn(f32) -> Message>>, +    width: Length, +} + +impl<'a, Message> Slider<'a, Message> { +    /// Creates a new [`Slider`]. +    /// +    /// It expects: +    ///   * the local [`State`] of the [`Slider`] +    ///   * an inclusive range of possible values +    ///   * the current value of the [`Slider`] +    ///   * a function that will be called when the [`Slider`] is dragged. +    ///   It receives the new value of the [`Slider`] and must produce a +    ///   `Message`. +    /// +    /// [`Slider`]: struct.Slider.html +    /// [`State`]: struct.State.html +    pub fn new<F>( +        state: &'a mut State, +        range: RangeInclusive<f32>, +        value: f32, +        on_change: F, +    ) -> Self +    where +        F: 'static + Fn(f32) -> Message, +    { +        Slider { +            _state: state, +            value: value.max(*range.start()).min(*range.end()), +            range, +            on_change: Rc::new(Box::new(on_change)), +            width: Length::Fill, +        } +    } + +    /// Sets the width of the [`Slider`]. +    /// +    /// [`Slider`]: struct.Slider.html +    pub fn width(mut self, width: Length) -> Self { +        self.width = width; +        self +    } +}  impl<'a, Message> Widget<Message> for Slider<'a, Message>  where @@ -60,3 +107,11 @@ where          Element::new(slider)      }  } + +pub struct State; + +impl State { +    pub fn new() -> Self { +        Self +    } +} diff --git a/web/src/widget/text.rs b/web/src/widget/text.rs index 41ccd6fc..1183a3cd 100644 --- a/web/src/widget/text.rs +++ b/web/src/widget/text.rs @@ -1,7 +1,111 @@ -use crate::{Bus, Element, Widget}; +use crate::{ +    Bus, Color, Element, Font, HorizontalAlignment, Length, VerticalAlignment, +    Widget, +};  use dodrio::bumpalo; -pub use iced_core::text::*; +/// A paragraph of text. +/// +/// # Example +/// +/// ``` +/// # use iced_web::Text; +/// +/// Text::new("I <3 iced!") +///     .size(40); +/// ``` +#[derive(Debug, Clone)] +pub struct Text { +    content: String, +    size: Option<u16>, +    color: Option<Color>, +    font: Font, +    width: Length, +    height: Length, +    horizontal_alignment: HorizontalAlignment, +    vertical_alignment: VerticalAlignment, +} + +impl Text { +    /// Create a new fragment of [`Text`] with the given contents. +    /// +    /// [`Text`]: struct.Text.html +    pub fn new<T: Into<String>>(label: T) -> Self { +        Text { +            content: label.into(), +            size: None, +            color: None, +            font: Font::Default, +            width: Length::Fill, +            height: Length::Shrink, +            horizontal_alignment: HorizontalAlignment::Left, +            vertical_alignment: VerticalAlignment::Top, +        } +    } + +    /// Sets the size of the [`Text`]. +    /// +    /// [`Text`]: struct.Text.html +    pub fn size(mut self, size: u16) -> Self { +        self.size = Some(size); +        self +    } + +    /// Sets the [`Color`] of the [`Text`]. +    /// +    /// [`Text`]: struct.Text.html +    /// [`Color`]: ../../struct.Color.html +    pub fn color<C: Into<Color>>(mut self, color: C) -> Self { +        self.color = Some(color.into()); +        self +    } + +    /// Sets the [`Font`] of the [`Text`]. +    /// +    /// [`Text`]: struct.Text.html +    /// [`Font`]: ../../struct.Font.html +    pub fn font(mut self, font: Font) -> Self { +        self.font = font; +        self +    } + +    /// Sets the width of the [`Text`] boundaries. +    /// +    /// [`Text`]: struct.Text.html +    pub fn width(mut self, width: Length) -> Self { +        self.width = width; +        self +    } + +    /// Sets the height of the [`Text`] boundaries. +    /// +    /// [`Text`]: struct.Text.html +    pub fn height(mut self, height: Length) -> Self { +        self.height = height; +        self +    } + +    /// Sets the [`HorizontalAlignment`] of the [`Text`]. +    /// +    /// [`Text`]: struct.Text.html +    /// [`HorizontalAlignment`]: enum.HorizontalAlignment.html +    pub fn horizontal_alignment( +        mut self, +        alignment: HorizontalAlignment, +    ) -> Self { +        self.horizontal_alignment = alignment; +        self +    } + +    /// Sets the [`VerticalAlignment`] of the [`Text`]. +    /// +    /// [`Text`]: struct.Text.html +    /// [`VerticalAlignment`]: enum.VerticalAlignment.html +    pub fn vertical_alignment(mut self, alignment: VerticalAlignment) -> Self { +        self.vertical_alignment = alignment; +        self +    } +}  impl<'a, Message> Widget<Message> for Text {      fn node<'b>( | 
